Compare commits
22 Commits
v7.0.0.1
...
v7.0.0.4-b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a3b9c653fa | ||
|
|
ed48f5c559 | ||
|
|
d328f6b7ec | ||
|
|
16ba94d67d | ||
|
|
7978170133 | ||
|
|
ab313eb442 | ||
|
|
f40008d94a | ||
|
|
75e19d8d18 | ||
|
|
9bb978f612 | ||
|
|
7ea3fbc917 | ||
|
|
3af5b458ba | ||
|
|
b23542d681 | ||
|
|
e0616dee76 | ||
|
|
cd54e67b87 | ||
|
|
9d4779fd96 | ||
|
|
d4d147e5fc | ||
|
|
35b17bc620 | ||
|
|
3eb4af5e75 | ||
|
|
49f22a1f81 | ||
|
|
7cd5686488 | ||
|
|
0d63feec57 | ||
|
|
0ee8318ca4 |
@@ -1,4 +1,52 @@
|
||||
|
||||
# v7.0.0.4 Beta (2023-12-19)
|
||||
|
||||
- When mpv.net is started for the first time from a new startup location,
|
||||
it asks if file associations should be registered.
|
||||
- Setup supports installing per user in non admin mode.
|
||||
- Command line parser supports list options with `-add` suffix.
|
||||
- Fix window sometimes shown with wrong size.
|
||||
- Limited support for the mpv option `geometry`, it supports location in percent,
|
||||
for size use `autofit`. Read the instructions in the mpv.net manual or in the conf editor.
|
||||
- Improved manual.
|
||||
- Improved bindings.
|
||||
- Conf editor reorganized according to options categories used in mpv manual.
|
||||
- mpv.net is available via command line package manager winget.
|
||||
- New libplacebo config editor options added.
|
||||
- The conf editor uses a newly developed combo box control (dropdown menu)
|
||||
instead of radio buttons whenever an option has more than 3 items,
|
||||
this improves the look and feel, usability and performance.
|
||||
The navigation tree view was improved.
|
||||
- New zhongfly libmpv build.
|
||||
|
||||
|
||||
# v7.0.0.3 Beta (2023-12-15)
|
||||
|
||||
- New conf editor option `Video/libplacebo/preset`.
|
||||
- New conf editor option `Video/libplacebo/Scaling/upscaler`.
|
||||
- New menu item `Settings/Setup/Add mpv.net to Path environment variable' added.
|
||||
- New menu item `Settings/Edit mpv.conf` added for opening mpv.conf with a text editor. Default binding `c`.
|
||||
- New menu item `Settings/Edit input.conf` added for opening input.conf with a text editor. Default binding `k`.
|
||||
- mpv.net can no longer be downloaded from the Microsoft store due
|
||||
to a general very poor experience with the package creation and submission.
|
||||
I've submitted mpv.net to the winget package repository, it's not yet processed.
|
||||
- Improved conf file reader/writer.
|
||||
- Conf editor support added for the mpv options:
|
||||
`reset-on-next-file`, `input-ipc-server`, `background`, `title`
|
||||
- Conf editor crash fixed.
|
||||
- When mpv.net is started for the first time from a new startup location,
|
||||
it asks if mpv.net should be added to the Path environment variable.
|
||||
|
||||
# v7.0.0.2 Beta (2023-12-13)
|
||||
|
||||
- Besides a portable download there is now again a setup installer.
|
||||
- Fix dynamic menu items missing in context menu.
|
||||
- Fix certain binding setups shown poorly or incorrectly in the main menu.
|
||||
- Fix conf editor not remembering the search text.
|
||||
- Fix quit-watch-later not working.
|
||||
- New option `menu-syntax`. Default: `#menu:`
|
||||
- New zhongfly libmpv build.
|
||||
|
||||
# v7.0.0.1 Beta (2023-12-11)
|
||||
|
||||
- [.NET 6 is a new requirement](https://dotnet.microsoft.com/en-us/download/dotnet/6.0)
|
||||
@@ -12,7 +60,7 @@
|
||||
- Fix message box exceding working area size.
|
||||
- C# and PowerShell scripting was removed because of a compatibility problem
|
||||
with the .NET 6 platform. .NET extensions are supported with a new host
|
||||
(not backward compatible). A example extension is available under \src\MpvNet.Extension\ExampleExtension
|
||||
(not backward compatible). An example extension is available under \src\MpvNet.Extension\ExampleExtension
|
||||
- Redesigned bindings and context menu.
|
||||
- auto-play option removed, mpv supports it with the option reset-on-next-file.
|
||||
- Dark mode title bar enabled on Windows 10.0.18985 or higher.
|
||||
|
||||
129
docs/manual.md
@@ -25,6 +25,7 @@ Table of contents
|
||||
* [Hidden Features](#hidden-features)
|
||||
* [Differences compared to mpv](#differences-compared-to-mpv)
|
||||
* [Environment Variables](#environment-variables)
|
||||
* [user-data](#user-data)
|
||||
* [Context Menu Commands](#context-menu)
|
||||
|
||||
|
||||
@@ -42,13 +43,9 @@ differences are documented in this manual under [Differences compared to mpv](#d
|
||||
Download
|
||||
--------
|
||||
|
||||
1. [Stable via Microsoft Store](https://www.microsoft.com/store/productId/9N64SQZTB3LM)
|
||||
|
||||
2. [Stable and beta portable via GitHub download](../../../releases)
|
||||
|
||||
3. Stable via command line from Microsoft Store: `winget install mpv.net`
|
||||
|
||||
4. [Automated nightly portable builds](https://github.com/mpvnet-player/mpv.net/actions)
|
||||
1. [Stable and beta portable and setup via GitHub download](../../../releases)
|
||||
2. Stable via command line with winget: `winget install mpv.net`
|
||||
3. [Automated nightly portable builds](https://github.com/mpvnet-player/mpv.net/actions)
|
||||
|
||||
[Changelog](changelog.md)
|
||||
|
||||
@@ -56,10 +53,8 @@ Download
|
||||
Installation
|
||||
------------
|
||||
|
||||
1. Windows 7 or higher is required (Windows 10 or higher is recommended).
|
||||
2. mpv.net since version 7.0 requires the
|
||||
[.NET Desktop Runtime 6.0](https://dotnet.microsoft.com/en-us/download/dotnet/6.0)
|
||||
being installed. mpv.net before version 7.0 requires .NET Framework 4.8.
|
||||
1. Windows 10 or higher.
|
||||
2. [.NET Desktop Runtime 6.0](https://dotnet.microsoft.com/en-us/download/dotnet/6.0)
|
||||
|
||||
Internet streaming requires:
|
||||
|
||||
@@ -71,8 +66,8 @@ Internet streaming requires:
|
||||
|
||||
File Associations can be registered using the context menu under 'Settings > Setup'.
|
||||
|
||||
After the file associations were registered, it might be necessary to change the
|
||||
default app in the Windows settings (Win+I, ms-settings:defaultapps).
|
||||
After the file associations were registered, it might still be necessary to change the
|
||||
default app in the Windows settings.
|
||||
|
||||
Another way to register file associations is using Windows File Explorer,
|
||||
select a media file and select 'Open with > Choose another app' in the context menu.
|
||||
@@ -84,6 +79,11 @@ to get menu items for [Play with mpv.net](https://github.com/stax76/OpenWithPlus
|
||||
When multiple files are selected in File Explorer and enter is pressed then
|
||||
the files are opened in mpv.net in random order, this works with maximum 15 files.
|
||||
|
||||
#### Path environment variable
|
||||
|
||||
In order to use mpv.net in a terminal for advanced use cases,
|
||||
mpv.net must be added to the Path environment variable,
|
||||
this can be achieved with the context menu (Settings/Setup).
|
||||
|
||||
Support
|
||||
-------
|
||||
@@ -110,8 +110,9 @@ Settings
|
||||
|
||||
mpv.net searches the config folder at:
|
||||
|
||||
1. startup\portable_config
|
||||
2. %APPDATA%\mpv.net (`C:\Users\%USERNAME%\AppData\Roaming\mpv.net`)
|
||||
1. Folder defined via MPVNET_HOME environment variable.
|
||||
2. startup\portable_config (startup means the directory containing mpvnet.exe)
|
||||
3. `%APPDATA%\mpv.net` (`C:\Users\Username\AppData\Roaming\mpv.net`)
|
||||
|
||||
mpv options are stored in the file mpv.conf,
|
||||
mpv.net options are stored in the file mpvnet.conf,
|
||||
@@ -121,7 +122,7 @@ mpv.net options are documented [here](#mpvnet-specific-options).
|
||||
Input and context menu
|
||||
----------------------
|
||||
|
||||
Global keyboard shortcuts are supported via global-input.conf file.
|
||||
Global keyboard shortcuts are supported via `global-input.conf` file.
|
||||
|
||||
The config folder can be opened from the context menu: `Settings > Open Config Folder`
|
||||
|
||||
@@ -141,24 +142,31 @@ mpv input options:
|
||||
https://mpv.io/manual/master/#input
|
||||
|
||||
Before version v7 all bindings and the context menu definition
|
||||
was contained in the input.conf file, which mpv.net created
|
||||
were defined in the input.conf file, which mpv.net created
|
||||
in case it didn't exist. This had the disadvantage that mpv.net
|
||||
lost control over all default bindings and the context menu
|
||||
defaults. This was unfortunate, v7 introduces a new design
|
||||
fixing it.
|
||||
lost control over all default bindings and context menu
|
||||
defaults. This was unfortunate, v7 introduces a new bindings
|
||||
and context menu design fixing it.
|
||||
|
||||
In v7 no input.conf file is created, the default bindings and
|
||||
context menu is defined internally. input.conf only contains
|
||||
what is different from the internally defined defaults,
|
||||
so it's the same how mpv is used.
|
||||
so it works the same it work with mpv.
|
||||
|
||||
For backward compatibility the old input.conf format with the
|
||||
menu definition using `#menu: ` is still supported. The new
|
||||
design also allows for a menu customization, in a sub section
|
||||
called `Custom`. In input.conf it can be defined like so:
|
||||
For backward compatibility the old input.conf context menu
|
||||
format with the menu definition using `#menu: ` is still
|
||||
supported. The new design also allows for a menu customization,
|
||||
in a sub section called `Custom`. In input.conf it can be
|
||||
defined like so:
|
||||
|
||||
`Ctrl+a show-text Test #custom-menu: Test > Test`
|
||||
|
||||
Users that have their bindings and context menu customized
|
||||
before v7 can easily migrate to the new design by deleting
|
||||
bindings they don't use and remember the shortcut and remove
|
||||
`#menu:` everywhere, it's important to remove `#menu:`
|
||||
everywhere in order to enable the new mode/design.
|
||||
|
||||
|
||||
Command Line Interface
|
||||
----------------------
|
||||
@@ -194,8 +202,6 @@ Terminal
|
||||
When mpv.net is started from a terminal it will output status,
|
||||
error and debug messages to the terminal and accept input keys from the terminal.
|
||||
|
||||
A common task for the terminal is debugging scripts.
|
||||
|
||||
|
||||
mpv.net specific commands
|
||||
-------------------------
|
||||
@@ -204,6 +210,12 @@ mpv.net specific commands
|
||||
|
||||
mpv.net commands are used when mpv commands don't exist or lack a feature.
|
||||
|
||||
### add-to-path
|
||||
Adds mpv.net to the Path environment variable.
|
||||
|
||||
### edit-conf-file [mpv.conf|input.conf]
|
||||
Opens mpv.conf or input.conf in a text editor.
|
||||
|
||||
### load-audio
|
||||
Shows a file browser dialog to open external audio files.
|
||||
|
||||
@@ -258,12 +270,6 @@ Shows available [mpv input commands](https://mpv.io/manual/master/#list-of-input
|
||||
### show-conf-editor
|
||||
Shows the conf editor.
|
||||
|
||||
### show-decoders
|
||||
Shows available decoders.
|
||||
|
||||
### show-demuxers
|
||||
Shows available demuxers.
|
||||
|
||||
### show-input-editor
|
||||
Shows the input editor.
|
||||
|
||||
@@ -390,6 +396,10 @@ For single files automatically load the entire directory into the playlist.
|
||||
|
||||
### General
|
||||
|
||||
#### --menu-syntax=\<value\>
|
||||
|
||||
Used menu syntax for defining the context menu in input.conf.\nmpv.net by default uses `#menu:`, uosc uses `#!` by default.
|
||||
|
||||
#### --process-instance=\<value\>
|
||||
|
||||
Defines if more then one mpv.net process is allowed.
|
||||
@@ -508,7 +518,8 @@ Scripting
|
||||
|
||||
#### Lua
|
||||
|
||||
A very large collection of Lua user scripts can be found in the mpv wiki [here](https://github.com/mpv-player/mpv/wiki/User-Scripts).
|
||||
A very large collection of user scripts can be found in the GitHub repository
|
||||
[awesome-mpv](https://github.com/stax76/awesome-mpv).
|
||||
|
||||
Lua scripting is documented in the mpv.net wiki [here](https://github.com/mpvnet-player/mpv.net/wiki/Extending-mpv-and-mpv.net-via-Lua-scripting).
|
||||
|
||||
@@ -517,10 +528,10 @@ Lua scripting is documented in the mpv.net wiki [here](https://github.com/mpvnet
|
||||
[mpv JavaScript documentation](https://mpv.io/manual/master/#javascript)
|
||||
|
||||
|
||||
Extensions
|
||||
----------
|
||||
.NET Extensions
|
||||
---------------
|
||||
|
||||
Extensions are located in a subfolder _extensions_ in the config folder,
|
||||
.NET Extensions are located in a subfolder _extensions_ in the config folder,
|
||||
the filename must have the same name as the directory:
|
||||
|
||||
```Text
|
||||
@@ -620,14 +631,32 @@ https://mpv.io/manual/master/#window
|
||||
- [window-scale](https://mpv.io/manual/master/#options-window-scale)
|
||||
|
||||
|
||||
**Partly implemented are:**
|
||||
**Partly implemented or modified:**
|
||||
|
||||
- [autofit-larger](https://mpv.io/manual/master/#options-autofit-larger)
|
||||
Supported is a single integer value in the range 0-100.
|
||||
- [autofit-smaller](https://mpv.io/manual/master/#options-autofit-smaller)
|
||||
Supported is a single integer value in the range 0-100.
|
||||
- [autofit](https://mpv.io/manual/master/#options-autofit)
|
||||
Supported is a single integer value in the range 0-100.
|
||||
#### --autofit=\<int\>
|
||||
|
||||
\<int\> Initial window height in percent. Default: 60
|
||||
|
||||
#### --autofit-smaller=\<int\>
|
||||
|
||||
\<int\> Minimum window height in percent. Default: 10
|
||||
|
||||
#### --autofit-larger=\<int\>
|
||||
|
||||
\<int\> Maximum window height in percent. Default: 80
|
||||
|
||||
#### --geometry\<x:y\>
|
||||
|
||||
Initial window location in percent. Default: 50:50 (centered)
|
||||
|
||||
x=0 docks the window to the left side.
|
||||
x=100 docks the window to the right side.
|
||||
|
||||
y=0 docks the window to the top side.
|
||||
y=100 docks the window to the bottom side.
|
||||
|
||||
|
||||
**mpv.net specific window features:**
|
||||
|
||||
mpv.net specific window features are documented in the [screen section](#screen).
|
||||
|
||||
@@ -672,10 +701,18 @@ Environment Variables
|
||||
|
||||
Directory where mpv.net looks for user settings.
|
||||
|
||||
### MPVNET_VERSION
|
||||
|
||||
Returns the version of mpv.net.
|
||||
user-data
|
||||
---------
|
||||
|
||||
Script authors can access the following
|
||||
[user-data](https://mpv.io/manual/master/#command-interface-user-data) properties:
|
||||
|
||||
```
|
||||
user-data/frontend/name
|
||||
user-data/frontend/version
|
||||
user-data/frontend/process-path
|
||||
```
|
||||
|
||||
Context Menu Commands
|
||||
---------------------
|
||||
|
||||
@@ -23,3 +23,12 @@ dotnet_diagnostic.IDE0044.severity = silent
|
||||
|
||||
# Member does not access instance data and can be marked as static
|
||||
dotnet_diagnostic.CA1822.severity = none
|
||||
|
||||
# IDE0057: Use range operator
|
||||
csharp_style_prefer_range_operator = false
|
||||
|
||||
# CA1401: P/Invokes should not be visible
|
||||
dotnet_diagnostic.CA1401.severity = none
|
||||
|
||||
# IDE0017: Simplify object initialization
|
||||
dotnet_style_object_initializer = false
|
||||
|
||||
@@ -53,6 +53,7 @@ public class Conf
|
||||
if (section.HasName("help")) baseSetting.Help = section.GetValue("help");
|
||||
if (section.HasName("url")) baseSetting.URL = section.GetValue("url");
|
||||
if (section.HasName("width")) baseSetting.Width = Convert.ToInt32(section.GetValue("width"));
|
||||
if (section.HasName("option-name-width")) baseSetting.OptionNameWidth = Convert.ToInt32(section.GetValue("option-name-width"));
|
||||
if (section.HasName("type")) baseSetting.Type = section.GetValue("type");
|
||||
|
||||
if (baseSetting.Help.ContainsEx("\\n"))
|
||||
@@ -90,6 +91,9 @@ public class ConfParser
|
||||
{
|
||||
string line = it.Trim();
|
||||
|
||||
if (line.StartsWith('#'))
|
||||
continue;
|
||||
|
||||
if (line == "")
|
||||
{
|
||||
currentGroup = new ConfSection();
|
||||
|
||||
@@ -11,6 +11,9 @@ using MpvNet.Windows.WinForms;
|
||||
using MpvNet.Windows.WPF.Views;
|
||||
using MpvNet.Windows.WPF;
|
||||
using MpvNet.Windows.WPF.MsgBox;
|
||||
using MpvNet.Help;
|
||||
using System.Text.Json;
|
||||
using MpvNet.Windows.Help;
|
||||
|
||||
namespace MpvNet;
|
||||
|
||||
@@ -45,6 +48,9 @@ public class GuiCommand
|
||||
["show-menu"] = args => ShowMenu?.Invoke(),
|
||||
["show-bindings"] = args => ShowBindings(),
|
||||
["show-playlist"] = args => ShowPlaylist(),
|
||||
["add-to-path"] = args => AddToPath(),
|
||||
["edit-conf-file"] = EditCongFile,
|
||||
["show-commands"] = args => ShowCommands(),
|
||||
|
||||
|
||||
// deprecated
|
||||
@@ -98,6 +104,53 @@ public class GuiCommand
|
||||
Player.LoadDiskFolder(dialog.SelectedPath);
|
||||
}
|
||||
|
||||
public void EditCongFile(IList<string> args)
|
||||
{
|
||||
string file = Player.ConfigFolder + args[0];
|
||||
|
||||
if (File.Exists(file))
|
||||
ProcessHelp.ShellExecute(WinApiHelp.GetAppPathForExtension("txt"), "\"" + file + "\"");
|
||||
}
|
||||
|
||||
public static void ShowTextWithEditor(string name, string text)
|
||||
{
|
||||
string file = Path.Combine(Path.GetTempPath(), name + ".txt");
|
||||
App.TempFiles.Add(file);
|
||||
File.WriteAllText(file, BR + text.Trim() + BR);
|
||||
ProcessHelp.ShellExecute(WinApiHelp.GetAppPathForExtension("txt"), "\"" + file + "\"");
|
||||
}
|
||||
|
||||
public static void ShowCommands()
|
||||
{
|
||||
string json = Core.GetPropertyString("command-list");
|
||||
var enumerator = JsonDocument.Parse(json).RootElement.EnumerateArray();
|
||||
var commands = enumerator.OrderBy(it => it.GetProperty("name").GetString());
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
foreach (var cmd in commands)
|
||||
{
|
||||
sb.AppendLine();
|
||||
sb.AppendLine(cmd.GetProperty("name").GetString());
|
||||
|
||||
foreach (var args in cmd.GetProperty("args").EnumerateArray())
|
||||
{
|
||||
string value = args.GetProperty("name").GetString() + " <" +
|
||||
args.GetProperty("type").GetString()!.ToLower() + ">";
|
||||
|
||||
if (args.GetProperty("optional").GetBoolean())
|
||||
value = "[" + value + "]";
|
||||
|
||||
sb.AppendLine(" " + value);
|
||||
}
|
||||
}
|
||||
|
||||
string header = BR +
|
||||
"https://mpv.io/manual/master/#list-of-input-commands" + BR2 +
|
||||
"https://github.com/stax76/mpv-scripts#command_palette" + BR;
|
||||
|
||||
ShowTextWithEditor("Input Commands", header + sb.ToString());
|
||||
}
|
||||
|
||||
public void OpenFromClipboard(IList<string> args)
|
||||
{
|
||||
if (System.Windows.Forms.Clipboard.ContainsFileDropList())
|
||||
@@ -248,7 +301,7 @@ public class GuiCommand
|
||||
text = text.TrimEx();
|
||||
|
||||
if (editor)
|
||||
Command.ShowTextWithEditor("media-info", text);
|
||||
ShowTextWithEditor("media-info", text);
|
||||
else if (osd)
|
||||
Command.ShowText(text.Replace("\r", ""), 5000, 16);
|
||||
else
|
||||
@@ -261,7 +314,24 @@ public class GuiCommand
|
||||
|
||||
public static string FormatTime(double value) => ((int)value).ToString("00");
|
||||
|
||||
public void ShowBindings() => Command.ShowTextWithEditor("Bindings", Player.UsedInputConfContent);
|
||||
public void ShowBindings() => ShowTextWithEditor("Bindings", Player.UsedInputConfContent);
|
||||
|
||||
public void AddToPath()
|
||||
{
|
||||
string path = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.User)!;
|
||||
|
||||
if (path.ToLower().Contains(Folder.Startup.TrimEnd(Path.DirectorySeparatorChar).ToLower()))
|
||||
{
|
||||
Msg.ShowWarning("mpv.net is already in Path.");
|
||||
return;
|
||||
}
|
||||
|
||||
Environment.SetEnvironmentVariable("Path",
|
||||
Folder.Startup.TrimEnd(Path.DirectorySeparatorChar) + ";" + path,
|
||||
EnvironmentVariableTarget.User);
|
||||
|
||||
Msg.ShowInfo("mpv.net successfully was added to Path.");
|
||||
}
|
||||
|
||||
public void ShowPlaylist()
|
||||
{
|
||||
|
||||
126
src/MpvNet.Windows/Help/WinApiHelp.cs
Normal file
@@ -0,0 +1,126 @@
|
||||
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
using static MpvNet.Windows.Native.WinApi;
|
||||
|
||||
namespace MpvNet.Windows.Help;
|
||||
|
||||
public class WinApiHelp
|
||||
{
|
||||
public static Version WindowsTen1607 { get; } = new Version(10, 0, 14393); // Windows 10 1607
|
||||
|
||||
public static int GetResizeBorder(int v)
|
||||
{
|
||||
switch (v)
|
||||
{
|
||||
case 1 /* WMSZ_LEFT */ : return 3;
|
||||
case 3 /* WMSZ_TOP */ : return 2;
|
||||
case 2 /* WMSZ_RIGHT */ : return 3;
|
||||
case 6 /* WMSZ_BOTTOM */ : return 2;
|
||||
case 4 /* WMSZ_TOPLEFT */ : return 1;
|
||||
case 5 /* WMSZ_TOPRIGHT */ : return 1;
|
||||
case 7 /* WMSZ_BOTTOMLEFT */ : return 3;
|
||||
case 8 /* WMSZ_BOTTOMRIGHT */ : return 3;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SubtractWindowBorders(IntPtr hwnd, ref Rect rc, int dpi)
|
||||
{
|
||||
Rect r = new Rect(0, 0, 0, 0);
|
||||
AddWindowBorders(hwnd, ref r, dpi);
|
||||
rc.Left -= r.Left;
|
||||
rc.Top -= r.Top;
|
||||
rc.Right -= r.Right;
|
||||
rc.Bottom -= r.Bottom;
|
||||
}
|
||||
|
||||
public static void AddWindowBorders(IntPtr hwnd, ref Rect rc, int dpi)
|
||||
{
|
||||
uint windowStyle = (uint)GetWindowLong(hwnd, -16); // GWL_STYLE
|
||||
uint windowStyleEx = (uint)GetWindowLong(hwnd, -20); // GWL_EXSTYLE
|
||||
|
||||
if (Environment.OSVersion.Version >= WindowsTen1607)
|
||||
AdjustWindowRectExForDpi(ref rc, windowStyle, false, windowStyleEx, (uint)dpi);
|
||||
else
|
||||
AdjustWindowRect(ref rc, windowStyle, false);
|
||||
}
|
||||
|
||||
public static Rectangle GetWorkingArea(IntPtr handle, Rectangle workingArea)
|
||||
{
|
||||
if (handle != IntPtr.Zero && GetDwmWindowRect(handle, out Rect dwmRect) &&
|
||||
GetWindowRect(handle, out Rect rect))
|
||||
{
|
||||
int left = workingArea.Left;
|
||||
int top = workingArea.Top;
|
||||
int right = workingArea.Right;
|
||||
int bottom = workingArea.Bottom;
|
||||
|
||||
left += rect.Left - dwmRect.Left;
|
||||
top -= rect.Top - dwmRect.Top;
|
||||
right -= dwmRect.Right - rect.Right;
|
||||
bottom -= dwmRect.Bottom - rect.Bottom;
|
||||
|
||||
return new Rectangle(left, top, right - left, bottom - top);
|
||||
}
|
||||
|
||||
return workingArea;
|
||||
}
|
||||
|
||||
public static bool GetDwmWindowRect(IntPtr handle, out Rect rect)
|
||||
{
|
||||
const uint DWMWA_EXTENDED_FRAME_BOUNDS = 9;
|
||||
|
||||
return 0 == DwmGetWindowAttribute(handle, DWMWA_EXTENDED_FRAME_BOUNDS,
|
||||
out rect, (uint)Marshal.SizeOf<Rect>());
|
||||
}
|
||||
|
||||
public static IntPtr GetWindowLong(IntPtr hWnd, int nIndex)
|
||||
{
|
||||
if (IntPtr.Size == 8)
|
||||
return GetWindowLongPtr(hWnd, nIndex);
|
||||
else
|
||||
return GetWindowLong32(hWnd, nIndex);
|
||||
}
|
||||
|
||||
public static IntPtr SetWindowLong(IntPtr hWnd, int nIndex, uint dwNewLong)
|
||||
{
|
||||
if (IntPtr.Size == 8)
|
||||
return SetWindowLongPtr(hWnd, nIndex, dwNewLong);
|
||||
else
|
||||
return SetWindowLong32(hWnd, nIndex, dwNewLong);
|
||||
}
|
||||
|
||||
public static string GetAppPathForExtension(params string[] extensions)
|
||||
{
|
||||
foreach (string it in extensions)
|
||||
{
|
||||
string extension = it;
|
||||
|
||||
if (!extension.StartsWith("."))
|
||||
extension = "." + extension;
|
||||
|
||||
uint c = 0U;
|
||||
|
||||
if (AssocQueryString(0x40, 2, extension, null, null, ref c) == 1)
|
||||
{
|
||||
if (c > 0L)
|
||||
{
|
||||
var sb = new StringBuilder((int)c);
|
||||
|
||||
if (0 == AssocQueryString(0x40, 2, extension, default, sb, ref c))
|
||||
{
|
||||
string ret = sb.ToString();
|
||||
|
||||
if (File.Exists(ret))
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,58 @@
|
||||
|
||||
using MpvNet.ExtensionMethod;
|
||||
using System.Windows;
|
||||
using MpvNet.Windows.WPF;
|
||||
|
||||
namespace MpvNet.Windows.Help;
|
||||
|
||||
public class WinMpvHelp
|
||||
{
|
||||
public static void CopyMpvNetCom()
|
||||
public static void Setup()
|
||||
{
|
||||
string dir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData).AddSep() +
|
||||
"Microsoft\\WindowsApps\\";
|
||||
string dir = RegistryHelp.GetString("PathEnvVarCheck"); // backward compatibility
|
||||
|
||||
if (File.Exists(dir + "mpvnet.exe") && !File.Exists(dir + "mpvnet.com"))
|
||||
File.Copy(Folder.Startup + "mpvnet.com", dir + "mpvnet.com");
|
||||
if (dir == Folder.Startup)
|
||||
return;
|
||||
|
||||
dir = RegistryHelp.GetString("Setup");
|
||||
|
||||
if (dir == Folder.Startup)
|
||||
return;
|
||||
|
||||
string path = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.User)!;
|
||||
|
||||
if (!path.ToLower().Contains(Folder.Startup.TrimEnd(Path.DirectorySeparatorChar).ToLower()))
|
||||
{
|
||||
var result = Msg.ShowQuestion("Would you like to add mpv.net to the Path environment variable?" + BR2 +
|
||||
"This will allow using mpv.net in a console/terminal.", MessageBoxButton.YesNo);
|
||||
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
Environment.SetEnvironmentVariable("Path",
|
||||
Folder.Startup.TrimEnd(Path.DirectorySeparatorChar) + ";" + path,
|
||||
EnvironmentVariableTarget.User);
|
||||
|
||||
Msg.ShowInfo("mpv.net was added successfully to Path.");
|
||||
}
|
||||
else
|
||||
Msg.ShowInfo("If you want to add mpv.net to the Path environment variable later," + BR +
|
||||
"you can do so with the context menu (Settings/Setup)");
|
||||
}
|
||||
|
||||
var result2 = Msg.ShowQuestion("Would you like to register video file associations?", MessageBoxButton.YesNo);
|
||||
|
||||
if (result2 == MessageBoxResult.Yes)
|
||||
{
|
||||
Player.Command("script-message-to mpvnet reg-file-assoc video");
|
||||
|
||||
result2 = Msg.ShowQuestion("Would you like to register audio file associations?", MessageBoxButton.YesNo);
|
||||
|
||||
if (result2 == MessageBoxResult.Yes)
|
||||
Player.Command("script-message-to mpvnet reg-file-assoc audio");
|
||||
}
|
||||
else
|
||||
Msg.ShowInfo("If you want to register file associations later," + BR +
|
||||
"you can do so with the context menu (Settings/Setup)");
|
||||
|
||||
RegistryHelp.SetString("Setup", Folder.Startup);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,11 +11,19 @@
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<ApplicationIcon>mpv-icon.ico</ApplicationIcon>
|
||||
<Product>mpv.net</Product>
|
||||
<AssemblyVersion>7.0.0.1</AssemblyVersion>
|
||||
<FileVersion>7.0.0.1</FileVersion>
|
||||
<FileVersion>7.0.0.4</FileVersion>
|
||||
<AssemblyVersion>7.0.0.4</AssemblyVersion>
|
||||
<InformationalVersion>7.0.0.4</InformationalVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Misc\**" />
|
||||
<EmbeddedResource Remove="Misc\**" />
|
||||
<None Remove="Misc\**" />
|
||||
<Page Remove="Misc\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="mpv-icon.ico" />
|
||||
</ItemGroup>
|
||||
@@ -38,8 +46,4 @@
|
||||
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.77" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Misc\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace MpvNet.Windows.Native;
|
||||
|
||||
public static class WinApi
|
||||
{
|
||||
public static Version WindowsTen1607 { get; } = new Version(10, 0, 14393); // Windows 10 1607
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern bool AttachConsole(int dwProcessId);
|
||||
|
||||
@@ -60,18 +59,10 @@ public static class WinApi
|
||||
IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags);
|
||||
|
||||
[DllImport("user32.dll", EntryPoint = "GetWindowLong")]
|
||||
static extern IntPtr GetWindowLong32(IntPtr hWnd, int nIndex);
|
||||
public static extern IntPtr GetWindowLong32(IntPtr hWnd, int nIndex);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
|
||||
|
||||
public static IntPtr GetWindowLong(IntPtr hWnd, int nIndex)
|
||||
{
|
||||
if (IntPtr.Size == 8)
|
||||
return GetWindowLongPtr(hWnd, nIndex);
|
||||
else
|
||||
return GetWindowLong32(hWnd, nIndex);
|
||||
}
|
||||
public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
|
||||
|
||||
[DllImport("user32.dll", EntryPoint = "SetWindowLong")]
|
||||
public static extern IntPtr SetWindowLong32(IntPtr hWnd, int nIndex, uint dwNewLong);
|
||||
@@ -79,50 +70,17 @@ public static class WinApi
|
||||
[DllImport("user32.dll")]
|
||||
public static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, uint dwNewLong);
|
||||
|
||||
public static IntPtr SetWindowLong(IntPtr hWnd, int nIndex, uint dwNewLong)
|
||||
{
|
||||
if (IntPtr.Size == 8)
|
||||
return SetWindowLongPtr(hWnd, nIndex, dwNewLong);
|
||||
else
|
||||
return SetWindowLong32(hWnd, nIndex, dwNewLong);
|
||||
}
|
||||
|
||||
[DllImport("gdi32.dll")]
|
||||
public static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
|
||||
|
||||
[DllImport("shlwapi", CharSet = CharSet.Auto)]
|
||||
public static extern uint AssocQueryString(
|
||||
uint flags, uint str, string? pszAssoc, string? pszExtra, [Out] StringBuilder? pszOut, ref uint pcchOut);
|
||||
|
||||
[DllImport("dwmapi.dll")]
|
||||
public static extern int DwmGetWindowAttribute(
|
||||
IntPtr hwnd, uint dwAttribute, out Rect pvAttribute, uint cbAttribute);
|
||||
|
||||
public static bool GetDwmWindowRect(IntPtr handle, out Rect rect)
|
||||
{
|
||||
const uint DWMWA_EXTENDED_FRAME_BOUNDS = 9;
|
||||
|
||||
return 0 == DwmGetWindowAttribute(handle, DWMWA_EXTENDED_FRAME_BOUNDS,
|
||||
out rect, (uint)Marshal.SizeOf<Rect>());
|
||||
}
|
||||
|
||||
public static Rectangle GetWorkingArea(IntPtr handle, Rectangle workingArea)
|
||||
{
|
||||
if (handle != IntPtr.Zero && GetDwmWindowRect(handle, out Rect dwmRect) &&
|
||||
GetWindowRect(handle, out Rect rect))
|
||||
{
|
||||
int left = workingArea.Left;
|
||||
int top = workingArea.Top;
|
||||
int right = workingArea.Right;
|
||||
int bottom = workingArea.Bottom;
|
||||
|
||||
left += rect.Left - dwmRect.Left;
|
||||
top -= rect.Top - dwmRect.Top;
|
||||
right -= dwmRect.Right - rect.Right;
|
||||
bottom -= dwmRect.Bottom - rect.Bottom;
|
||||
|
||||
return new Rectangle(left, top, right - left, bottom - top);
|
||||
}
|
||||
|
||||
return workingArea;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Rect
|
||||
{
|
||||
@@ -171,41 +129,4 @@ public static class WinApi
|
||||
[MarshalAs(UnmanagedType.LPTStr)]
|
||||
public string lpData;
|
||||
}
|
||||
|
||||
public static int GetResizeBorder(int v)
|
||||
{
|
||||
switch (v)
|
||||
{
|
||||
case 1 /* WMSZ_LEFT */ : return 3;
|
||||
case 3 /* WMSZ_TOP */ : return 2;
|
||||
case 2 /* WMSZ_RIGHT */ : return 3;
|
||||
case 6 /* WMSZ_BOTTOM */ : return 2;
|
||||
case 4 /* WMSZ_TOPLEFT */ : return 1;
|
||||
case 5 /* WMSZ_TOPRIGHT */ : return 1;
|
||||
case 7 /* WMSZ_BOTTOMLEFT */ : return 3;
|
||||
case 8 /* WMSZ_BOTTOMRIGHT */ : return 3;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SubtractWindowBorders(IntPtr hwnd, ref Rect rc, int dpi)
|
||||
{
|
||||
Rect r = new Rect(0, 0, 0, 0);
|
||||
AddWindowBorders(hwnd, ref r, dpi);
|
||||
rc.Left -= r.Left;
|
||||
rc.Top -= r.Top;
|
||||
rc.Right -= r.Right;
|
||||
rc.Bottom -= r.Bottom;
|
||||
}
|
||||
|
||||
public static void AddWindowBorders(IntPtr hwnd, ref Rect rc, int dpi)
|
||||
{
|
||||
uint windowStyle = (uint)GetWindowLong(hwnd, -16); // GWL_STYLE
|
||||
uint windowStyleEx = (uint)GetWindowLong(hwnd, -20); // GWL_EXSTYLE
|
||||
|
||||
if (Environment.OSVersion.Version >= WindowsTen1607)
|
||||
AdjustWindowRectExForDpi(ref rc, windowStyle, false, windowStyleEx, (uint)dpi);
|
||||
else
|
||||
AdjustWindowRect(ref rc, windowStyle, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 11 KiB |
@@ -1,137 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<Package
|
||||
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
|
||||
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
|
||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||
IgnorableNamespaces="uap rescap">
|
||||
|
||||
<Identity
|
||||
Name="5664FrankSkare.mpv.net"
|
||||
Publisher="CN=6A1A1E69-736C-4C77-B310-7B6D38E32617"
|
||||
Version="6.0.3.0" />
|
||||
|
||||
<Properties>
|
||||
<DisplayName>mpv.net</DisplayName>
|
||||
<PublisherDisplayName>Frank Skare</PublisherDisplayName>
|
||||
<Logo>Images\StoreLogo.png</Logo>
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.14393.0" MaxVersionTested="10.0.14393.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
<Resource Language="x-generate"/>
|
||||
</Resources>
|
||||
|
||||
<Applications>
|
||||
<Application Id="App"
|
||||
Executable="$targetnametoken$.exe"
|
||||
EntryPoint="$targetentrypoint$">
|
||||
<uap:VisualElements
|
||||
DisplayName="mpv.net"
|
||||
Description="mpv.net is a modern media player based on the popular mpv player."
|
||||
BackgroundColor="transparent"
|
||||
Square150x150Logo="Images\Square150x150Logo.png"
|
||||
Square44x44Logo="Images\Square44x44Logo.png">
|
||||
<uap:DefaultTile Wide310x150Logo="Images\Wide310x150Logo.png" />
|
||||
<uap:SplashScreen Image="Images\SplashScreen.png" />
|
||||
</uap:VisualElements>
|
||||
|
||||
<Extensions>
|
||||
<uap3:Extension Category="windows.appExecutionAlias">
|
||||
<uap3:AppExecutionAlias>
|
||||
<desktop:ExecutionAlias Alias="MpvNet.exe" />
|
||||
</uap3:AppExecutionAlias>
|
||||
</uap3:Extension>
|
||||
|
||||
<uap:Extension Category="windows.fileTypeAssociation">
|
||||
<uap:FileTypeAssociation Name="videotypes">
|
||||
<uap:SupportedFileTypes>
|
||||
<uap:FileType>.264</uap:FileType>
|
||||
<uap:FileType>.265</uap:FileType>
|
||||
<uap:FileType>.asf</uap:FileType>
|
||||
<uap:FileType>.avc</uap:FileType>
|
||||
<uap:FileType>.avi</uap:FileType>
|
||||
<uap:FileType>.avs</uap:FileType>
|
||||
<uap:FileType>.dav</uap:FileType>
|
||||
<uap:FileType>.flv</uap:FileType>
|
||||
<uap:FileType>.h264</uap:FileType>
|
||||
<uap:FileType>.h265</uap:FileType>
|
||||
<uap:FileType>.hevc</uap:FileType>
|
||||
<uap:FileType>.m2t</uap:FileType>
|
||||
<uap:FileType>.m2ts</uap:FileType>
|
||||
<uap:FileType>.m2v</uap:FileType>
|
||||
<uap:FileType>.m4v</uap:FileType>
|
||||
<uap:FileType>.mkv</uap:FileType>
|
||||
<uap:FileType>.mov</uap:FileType>
|
||||
<uap:FileType>.mp4</uap:FileType>
|
||||
<uap:FileType>.mpeg</uap:FileType>
|
||||
<uap:FileType>.mpg</uap:FileType>
|
||||
<uap:FileType>.mpv</uap:FileType>
|
||||
<uap:FileType>.mts</uap:FileType>
|
||||
<uap:FileType>.ts</uap:FileType>
|
||||
<uap:FileType>.vob</uap:FileType>
|
||||
<uap:FileType>.vpy</uap:FileType>
|
||||
<uap:FileType>.webm</uap:FileType>
|
||||
<uap:FileType>.wmv</uap:FileType>
|
||||
<uap:FileType>.y4m</uap:FileType>
|
||||
</uap:SupportedFileTypes>
|
||||
</uap:FileTypeAssociation>
|
||||
</uap:Extension>
|
||||
|
||||
<uap:Extension Category="windows.fileTypeAssociation">
|
||||
<uap:FileTypeAssociation Name="audiotypes">
|
||||
<uap:SupportedFileTypes>
|
||||
<uap:FileType>.aac</uap:FileType>
|
||||
<uap:FileType>.ac3</uap:FileType>
|
||||
<uap:FileType>.dts</uap:FileType>
|
||||
<uap:FileType>.dtshd</uap:FileType>
|
||||
<uap:FileType>.dtshr</uap:FileType>
|
||||
<uap:FileType>.dtsma</uap:FileType>
|
||||
<uap:FileType>.eac3</uap:FileType>
|
||||
<uap:FileType>.flac</uap:FileType>
|
||||
<uap:FileType>.m4a</uap:FileType>
|
||||
<uap:FileType>.mka</uap:FileType>
|
||||
<uap:FileType>.mp2</uap:FileType>
|
||||
<uap:FileType>.mp3</uap:FileType>
|
||||
<uap:FileType>.mpa</uap:FileType>
|
||||
<uap:FileType>.mpc</uap:FileType>
|
||||
<uap:FileType>.ogg</uap:FileType>
|
||||
<uap:FileType>.opus</uap:FileType>
|
||||
<uap:FileType>.thd</uap:FileType>
|
||||
<uap:FileType>.w64</uap:FileType>
|
||||
<uap:FileType>.wav</uap:FileType>
|
||||
</uap:SupportedFileTypes>
|
||||
</uap:FileTypeAssociation>
|
||||
</uap:Extension>
|
||||
|
||||
<uap:Extension Category="windows.protocol">
|
||||
<uap:Protocol Name="ytdl" />
|
||||
</uap:Extension>
|
||||
|
||||
<uap:Extension Category="windows.protocol">
|
||||
<uap:Protocol Name="rtsp" />
|
||||
</uap:Extension>
|
||||
|
||||
<uap:Extension Category="windows.protocol">
|
||||
<uap:Protocol Name="srt" />
|
||||
</uap:Extension>
|
||||
|
||||
<uap:Extension Category="windows.protocol">
|
||||
<uap:Protocol Name="srtp" />
|
||||
</uap:Extension>
|
||||
</Extensions>
|
||||
|
||||
</Application>
|
||||
</Applications>
|
||||
|
||||
<Capabilities>
|
||||
<Capability Name="internetClient" />
|
||||
<rescap:Capability Name="runFullTrust" />
|
||||
</Capabilities>
|
||||
</Package>
|
||||
@@ -1,78 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Condition="'$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' < '15.0'">
|
||||
<VisualStudioVersion>15.0</VisualStudioVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<WapProjPath Condition="'$(WapProjPath)'==''">$(MSBuildExtensionsPath)\Microsoft\DesktopBridge\</WapProjPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.props" />
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>81daee3a-76ff-4494-9384-d28a651d70bb</ProjectGuid>
|
||||
<TargetPlatformVersion>10.0.22000.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.14393.0</TargetPlatformMinVersion>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
<AppxPackageSigningEnabled>false</AppxPackageSigningEnabled>
|
||||
<EntryPointProjectUniqueName>..\mpv.net.csproj</EntryPointProjectUniqueName>
|
||||
<GenerateAppInstallerFile>False</GenerateAppInstallerFile>
|
||||
<AppxAutoIncrementPackageRevision>False</AppxAutoIncrementPackageRevision>
|
||||
<GenerateTestArtifacts>True</GenerateTestArtifacts>
|
||||
<AppxBundlePlatforms>x64</AppxBundlePlatforms>
|
||||
<GenerateTemporaryStoreCertificate>True</GenerateTemporaryStoreCertificate>
|
||||
<HoursBetweenUpdateChecks>0</HoursBetweenUpdateChecks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<AppxBundle>Always</AppxBundle>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<AppxBundle>Always</AppxBundle>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<AppxManifest Include="Package.appxmanifest">
|
||||
<SubType>Designer</SubType>
|
||||
</AppxManifest>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="..\bin\MediaInfo.dll">
|
||||
<Link>mpv.net\MediaInfo.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="..\bin\Microsoft.Management.Infrastructure.dll">
|
||||
<Link>mpv.net\Microsoft.Management.Infrastructure.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="..\bin\libmpv-2.dll">
|
||||
<Link>mpv.net\libmpv-2.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="..\bin\mpvnet.com">
|
||||
<Link>mpv.net\mpvnet.com</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Images\SplashScreen.scale-200.png" />
|
||||
<Content Include="Images\LockScreenLogo.scale-200.png" />
|
||||
<Content Include="Images\Square150x150Logo.scale-200.png" />
|
||||
<Content Include="Images\Square44x44Logo.scale-200.png" />
|
||||
<Content Include="Images\Square44x44Logo.targetsize-24_altform-unplated.png" />
|
||||
<Content Include="Images\StoreLogo.png" />
|
||||
<Content Include="Images\Wide310x150Logo.scale-200.png" />
|
||||
<None Include="Package.StoreAssociation.xml" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.targets" />
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.19041.8" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\mpv.net.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -7,7 +7,6 @@ using MpvNet.Help;
|
||||
using MpvNet.Windows.UI;
|
||||
using MpvNet.Windows.Help;
|
||||
using MpvNet.Windows.WPF;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace MpvNet.Windows;
|
||||
|
||||
@@ -97,10 +96,13 @@ static class Program
|
||||
return;
|
||||
}
|
||||
|
||||
if (App.CommandLine.Contains("--o="))
|
||||
if (ProcessCommandLineArguments())
|
||||
Environment.GetCommandLineArgs();
|
||||
else if (App.CommandLine.Contains("--o="))
|
||||
{
|
||||
App.AutoLoadFolder = false;
|
||||
Player.Init(IntPtr.Zero);
|
||||
Player.ProcessCommandLineArgsPost();
|
||||
Player.ProcessCommandLineFiles();
|
||||
Player.SetPropertyString("idle", "no");
|
||||
Player.EventLoop();
|
||||
@@ -119,4 +121,48 @@ static class Program
|
||||
Terminal.WriteError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static bool ProcessCommandLineArguments()
|
||||
{
|
||||
foreach (string arg in Environment.GetCommandLineArgs().Skip(1))
|
||||
{
|
||||
if (arg == "--profile=help")
|
||||
{
|
||||
Player.Init(IntPtr.Zero, false);
|
||||
Console.WriteLine(Player.GetProfiles());
|
||||
Player.Destroy();
|
||||
return true;
|
||||
}
|
||||
else if (arg == "--vd=help" || arg == "--ad=help")
|
||||
{
|
||||
Player.Init(IntPtr.Zero, false);
|
||||
Console.WriteLine(Player.GetDecoders());
|
||||
Player.Destroy();
|
||||
return true;
|
||||
}
|
||||
else if (arg == "--audio-device=help")
|
||||
{
|
||||
Player.Init(IntPtr.Zero, false);
|
||||
Console.WriteLine(Player.GetPropertyOsdString("audio-device-list"));
|
||||
Player.Destroy();
|
||||
return true;
|
||||
}
|
||||
else if (arg == "--input-keylist")
|
||||
{
|
||||
Player.Init(IntPtr.Zero, false);
|
||||
Console.WriteLine(Player.GetPropertyString("input-key-list").Replace(",", BR));
|
||||
Player.Destroy();
|
||||
return true;
|
||||
}
|
||||
else if (arg == "--version")
|
||||
{
|
||||
Player.Init(IntPtr.Zero, false);
|
||||
Console.WriteLine(AppClass.About);
|
||||
Player.Destroy();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
7
src/MpvNet.Windows/Properties/launchSettings.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"profiles": {
|
||||
"MpvNet.Windows": {
|
||||
"commandName": "Project"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ name = process-instance
|
||||
file = mpvnet
|
||||
default = single
|
||||
directory = General
|
||||
help = Defines if more then one mpv.net process is allowed. (mpv.net option)\n\nMulti can alternatively be enabled by pressing the SHIFT key.
|
||||
help = Defines if more then one mpv.net process is allowed.\nMulti can alternatively be enabled by pressing the SHIFT key. (mpv.net option)
|
||||
option = multi Create a new process everytime the shell starts mpv.net
|
||||
option = single Force a single process everytime the shell starts mpv.net
|
||||
option = queue Force a single process and add files to playlist
|
||||
@@ -39,6 +39,26 @@ directory = General
|
||||
width = 500
|
||||
help = Image file extensions used to create file associations and used by the auto-load-folder feature. (mpv.net option)
|
||||
|
||||
name = menu-syntax
|
||||
file = mpvnet
|
||||
directory = General
|
||||
help = Used menu syntax for defining the context menu in input.conf.\nmpv.net by default uses '#menu:', uosc uses '#!' by default.
|
||||
|
||||
name = video-sync
|
||||
file = mpv
|
||||
default = audio
|
||||
directory = General
|
||||
help = How the player synchronizes audio and video.\n\nFor more information visit:
|
||||
url = https://mpv.io/manual/master/#options-video-sync
|
||||
option = audio
|
||||
option = display-resample
|
||||
option = display-resample-vdrop
|
||||
option = display-resample-desync
|
||||
option = display-vdrop
|
||||
option = display-adrop
|
||||
option = display-desync
|
||||
option = desync
|
||||
|
||||
name = debug-mode
|
||||
file = mpvnet
|
||||
default = no
|
||||
@@ -68,20 +88,20 @@ option = auto enable best hw decoder
|
||||
option = yes exactly the same as auto
|
||||
option = auto-copy enable best hw decoder with copy-back
|
||||
option = auto-safe enable any whitelisted hw decoder
|
||||
option = dxva2 requires vo=gpu with gpu-context=d3d11, gpu-context=angle or gpu-context=dxinterop (Windows only)
|
||||
option = dxva2-copy copies video back to system RAM (Windows only)
|
||||
option = d3d11va requires vo=gpu with gpu-context=d3d11 or gpu-context=angle (Windows 8+ only)
|
||||
option = d3d11va-copy copies video back to system RAM (Windows 8+ only)
|
||||
option = dxva2 requires vo=gpu with gpu-context=d3d11, gpu-context=angle or gpu-context=dxinterop
|
||||
option = dxva2-copy copies video back to system RAM
|
||||
option = d3d11va requires vo=gpu with gpu-context=d3d11 or gpu-context=angle
|
||||
option = d3d11va-copy copies video back to system RAM
|
||||
option = cuda requires vo=gpu (Any platform CUDA is available)
|
||||
option = cuda-copy copies video back to system RAM (Any platform CUDA is available)
|
||||
option = cuda-copy copies video back to system RAM
|
||||
option = nvdec requires vo=gpu (Any platform CUDA is available)
|
||||
option = nvdec-copy copies video back to system RAM (Any platform CUDA is available)
|
||||
option = nvdec-copy copies video back to system RAM
|
||||
|
||||
name = gpu-api
|
||||
file = mpv
|
||||
default = auto
|
||||
directory = Video
|
||||
help = Controls which type of graphics APIs will be accepted. Auto uses d3d11, it should only be changed in case of problems, Vulkan is not recommended.
|
||||
directory = Video/Render Options
|
||||
help = Controls which type of graphics APIs will be accepted. On Windows this defaults to d3d11 and should not be changed without a good reason.
|
||||
option = auto Use any available API
|
||||
option = d3d11 Allow only gpu-context=d3d11
|
||||
option = opengl Allow only OpenGL (requires OpenGL 2.1+ or GLES 2.0+)
|
||||
@@ -90,7 +110,7 @@ option = vulkan Allow only Vulkan
|
||||
name = gpu-context
|
||||
file = mpv
|
||||
default = auto
|
||||
directory = Video
|
||||
directory = Video/Render Options
|
||||
option = auto auto-select
|
||||
option = d3d11 Win32, with native Direct3D 11 rendering.
|
||||
option = angle Direct3D11 through the OpenGL ES translation layer ANGLE. This supports almost everything the win backend does (if the ANGLE build is new enough).
|
||||
@@ -98,74 +118,52 @@ option = win Win32/WGL
|
||||
option = dxinterop (experimental) Win32, using WGL for rendering and Direct3D 9Ex for presentation. Works on Nvidia and AMD. Newer Intel chips with the latest drivers may also work.
|
||||
option = winvk VK_KHR_win32_surface
|
||||
|
||||
name = video-sync
|
||||
file = mpv
|
||||
default = audio
|
||||
directory = Video
|
||||
help = How the player synchronizes audio and video.\n\nFor more information visit:
|
||||
url = https://mpv.io/manual/master/#options-video-sync
|
||||
option = audio
|
||||
option = display-resample
|
||||
option = display-resample-vdrop
|
||||
option = display-resample-desync
|
||||
option = display-vdrop
|
||||
option = display-adrop
|
||||
option = display-desync
|
||||
option = desync
|
||||
|
||||
name = scale
|
||||
file = mpv
|
||||
default = bilinear
|
||||
directory = Video
|
||||
default = lanczos
|
||||
directory = Video/Render Options/Scaling
|
||||
help = The GPU renderer filter function to use when upscaling video. There are some more filters, but most are not as useful. For a complete list, pass help as value, e.g.: mpv --scale=help
|
||||
option = bilinear Bilinear hardware texture filtering (fastest, very low quality).
|
||||
option = spline36 Mid quality and speed. This is the default when using gpu-hq.
|
||||
option = lanczos Lanczos scaling. Provides mid quality and speed. Generally worse than spline36, but it results in a slightly sharper image which is good for some content types. The number of taps can be controlled with scale-radius, but is best left unchanged. (This filter is an alias for sinc-windowed sinc)
|
||||
option = ewa_lanczos Elliptic weighted average Lanczos scaling. Also known as Jinc. Relatively slow, but very good quality. The radius can be controlled with scale-radius. Increasing the radius makes the filter sharper but adds more ringing. (This filter is an alias for jinc-windowed jinc)
|
||||
option = ewa_lanczossharp A slightly sharpened version of ewa_lanczos, preconfigured to use an ideal radius and parameter. If your hardware can run it, this is probably what you should use by default.
|
||||
option = mitchell Mitchell-Netravali. The B and C parameters can be set with scale-param1 and scale-param2. This filter is very good at downscaling (see dscale).
|
||||
option = oversample A version of nearest neighbour that (naively) oversamples pixels, so that pixels overlapping edges get linearly interpolated instead of rounded. This essentially removes the small imperfections and judder artifacts caused by nearest-neighbour interpolation, in exchange for adding some blur. This filter is good at temporal interpolation, and also known as "smoothmotion" (see tscale).
|
||||
url = https://mpv.io/manual/master/#options-scale
|
||||
option = bilinear
|
||||
option = spline36
|
||||
option = lanczos
|
||||
option = ewa_lanczos
|
||||
option = ewa_lanczossharp
|
||||
option = mitchell
|
||||
option = oversample
|
||||
|
||||
name = cscale
|
||||
file = mpv
|
||||
default = bilinear
|
||||
directory = Video
|
||||
directory = Video/Render Options/Scaling
|
||||
help = As scale, but for interpolating chroma information. If the image is not subsampled, this option is ignored entirely.
|
||||
option = bilinear Bilinear hardware texture filtering (fastest, very low quality).
|
||||
option = spline36 Mid quality and speed. This is the default when using gpu-hq.
|
||||
option = lanczos Lanczos scaling. Provides mid quality and speed. Generally worse than spline36, but it results in a slightly sharper image which is good for some content types. The number of taps can be controlled with scale-radius, but is best left unchanged. (This filter is an alias for sinc-windowed sinc)
|
||||
option = ewa_lanczos Elliptic weighted average Lanczos scaling. Also known as Jinc. Relatively slow, but very good quality. The radius can be controlled with scale-radius. Increasing the radius makes the filter sharper but adds more ringing. (This filter is an alias for jinc-windowed jinc)
|
||||
option = ewa_lanczossharp A slightly sharpened version of ewa_lanczos, preconfigured to use an ideal radius and parameter. If your hardware can run it, this is probably what you should use by default.
|
||||
option = mitchell Mitchell-Netravali. The B and C parameters can be set with scale-param1 and scale-param2. This filter is very good at downscaling (see dscale).
|
||||
option = oversample A version of nearest neighbour that (naively) oversamples pixels, so that pixels overlapping edges get linearly interpolated instead of rounded. This essentially removes the small imperfections and judder artifacts caused by nearest-neighbour interpolation, in exchange for adding some blur. This filter is good at temporal interpolation, and also known as "smoothmotion" (see tscale).
|
||||
url = https://mpv.io/manual/master/#options-cscale
|
||||
option = bilinear
|
||||
option = spline36
|
||||
option = lanczos
|
||||
option = ewa_lanczos
|
||||
option = ewa_lanczossharp
|
||||
option = mitchell
|
||||
option = oversample
|
||||
|
||||
name = dscale
|
||||
file = mpv
|
||||
default =
|
||||
directory = Video
|
||||
default = lanczos
|
||||
directory = Video/Render Options/Scaling
|
||||
help = Like scale, but apply these filters on downscaling instead. \nIf no option is selected, it will keep the same with the upscaler.
|
||||
option = bilinear Bilinear hardware texture filtering (fastest, very low quality).
|
||||
option = spline36 Mid quality and speed. This is the default when using gpu-hq.
|
||||
option = lanczos Lanczos scaling. Provides mid quality and speed. Generally worse than spline36, but it results in a slightly sharper image which is good for some content types. The number of taps can be controlled with scale-radius, but is best left unchanged. (This filter is an alias for sinc-windowed sinc)
|
||||
option = ewa_lanczos Elliptic weighted average Lanczos scaling. Also known as Jinc. Relatively slow, but very good quality. The radius can be controlled with scale-radius. Increasing the radius makes the filter sharper but adds more ringing. (This filter is an alias for jinc-windowed jinc)
|
||||
option = ewa_lanczossharp A slightly sharpened version of ewa_lanczos, preconfigured to use an ideal radius and parameter. If your hardware can run it, this is probably what you should use by default.
|
||||
option = mitchell Mitchell-Netravali. The B and C parameters can be set with scale-param1 and scale-param2. This filter is very good at downscaling (see dscale).
|
||||
option = oversample A version of nearest neighbour that (naively) oversamples pixels, so that pixels overlapping edges get linearly interpolated instead of rounded. This essentially removes the small imperfections and judder artifacts caused by nearest-neighbour interpolation, in exchange for adding some blur. This filter is good at temporal interpolation, and also known as "smoothmotion" (see tscale).
|
||||
|
||||
name = dither-depth
|
||||
file = mpv
|
||||
default = no
|
||||
directory = Video
|
||||
help = Set dither target depth to N. Note that the depth of the connected video display device cannot be detected. Often, LCD panels will do dithering on their own, which conflicts with this option and leads to ugly output.
|
||||
option = no Disable any dithering done by mpv.
|
||||
option = auto Automatic selection. If output bit depth cannot be detected, 8 bits per component are assumed.
|
||||
option = 8 Dither to 8 bit output.
|
||||
option = 10 Dither to 10 bit output.
|
||||
url = https://mpv.io/manual/master/#options-dscale
|
||||
option = bilinear
|
||||
option = spline36
|
||||
option = lanczos
|
||||
option = ewa_lanczos
|
||||
option = ewa_lanczossharp
|
||||
option = mitchell
|
||||
option = oversample
|
||||
|
||||
name = correct-downscaling
|
||||
file = mpv
|
||||
default = no
|
||||
directory = Video
|
||||
directory = Video/Render Options/Scaling
|
||||
help = When using convolution based filters, extend the filter size when downscaling. Increases quality, but reduces performance while downscaling.\n\nThis will perform slightly sub-optimally for anamorphic video (but still better than without it) since it will extend the size to match only the milder of the scale factors between the axes.
|
||||
option = yes
|
||||
option = no
|
||||
@@ -173,32 +171,34 @@ option = no
|
||||
name = sigmoid-upscaling
|
||||
file = mpv
|
||||
default = no
|
||||
directory = Video
|
||||
directory = Video/Render Options/Scaling
|
||||
help = When upscaling, use a sigmoidal color transform to avoid emphasizing ringing artifacts. This also implies linear-scaling.
|
||||
option = yes
|
||||
option = no
|
||||
|
||||
name = dither-depth
|
||||
file = mpv
|
||||
default = no
|
||||
directory = Video/Render Options
|
||||
help = Set dither target depth to N. Note that the depth of the connected video display device cannot be detected. Often, LCD panels will do dithering on their own, which conflicts with this option and leads to ugly output.
|
||||
option = no Disable any dithering done by mpv.
|
||||
option = auto Automatic selection. If output bit depth cannot be detected, 8 bits per component are assumed.
|
||||
option = 8 Dither to 8 bit output.
|
||||
option = 10 Dither to 10 bit output.
|
||||
|
||||
name = deband
|
||||
file = mpv
|
||||
default = no
|
||||
directory = Video
|
||||
directory = Video/Render Options
|
||||
help = Enable the debanding algorithm. This greatly reduces the amount of visible banding, blocking and other quantization artifacts, at the expense of very slightly blurring some of the finest details. In practice, it's virtually always an improvement - the only reason to disable it would be for performance.
|
||||
option = yes
|
||||
option = no
|
||||
|
||||
name = d3d11va-zero-copy
|
||||
file = mpv
|
||||
default = no
|
||||
directory = Video
|
||||
help = By default, when using hardware decoding with --gpu-api=d3d11, the video image will be copied (GPU-to-GPU) from the decoder surface to a shader resource. Set this option to avoid that copy by sampling directly from the decoder image. This may increase performance and reduce power usage, but can cause the image to be sampled incorrectly on the bottom and right edges due to padding, and may invoke driver bugs, since Direct3D 11 technically does not allow sampling from a decoder surface (though most drivers support it.)
|
||||
option = yes
|
||||
option = no
|
||||
|
||||
name = hdr-compute-peak
|
||||
file = mpv
|
||||
default = auto
|
||||
directory = Video
|
||||
help = Compute the HDR peak and frame average brightness per-frame instead of relying on tagged metadata. These values are averaged over local regions as well as over several frames to prevent the value from jittering around too much. This option basically gives you dynamic, per-scene tone mapping. Requires compute shaders, which is a fairly recent OpenGL feature, and will probably also perform horribly on some drivers, so enable at your own risk. The special value auto (default) will enable HDR peak computation automatically if compute shaders and SSBOs are supported.
|
||||
directory = Video/Render Options
|
||||
url = https://mpv.io/manual/master/#options-hdr-compute-peak
|
||||
option = auto
|
||||
option = yes
|
||||
option = no
|
||||
@@ -206,11 +206,226 @@ option = no
|
||||
name = allow-delayed-peak-detect
|
||||
file = mpv
|
||||
default = yes
|
||||
directory = Video
|
||||
help = When using --hdr-compute-peak, allow delaying the detected peak by a frame when beneficial for performance. In particular, this is required to avoid an unnecessary FBO indirection when no advanced rendering is required otherwise. Has no effect if there already is an indirect pass, such as when advanced scaling is enabled. (Only affects --vo=gpu-next, note that --vo=gpu always delays the peak.)
|
||||
directory = Video/Render Options
|
||||
url = https://mpv.io/manual/master/#options-allow-delayed-peak-detect
|
||||
option = yes
|
||||
option = no
|
||||
|
||||
name = d3d11va-zero-copy
|
||||
file = mpv
|
||||
default = no
|
||||
directory = Video/Render Options
|
||||
url = https://mpv.io/manual/master/#options-d3d11va-zero-copy
|
||||
option = yes
|
||||
option = no
|
||||
|
||||
name = background
|
||||
file = mpv
|
||||
directory = Video/Render Options
|
||||
help = Color used to draw parts of the mpv window not covered by video. See the --sub-color option for how colors are defined.
|
||||
|
||||
name = libplacebo-opts
|
||||
file = mpv
|
||||
directory = Video/Render Options
|
||||
help = Passes extra raw option to the libplacebo rendering backend (used by --vo=gpu-next). May override the effects of any other options set using the normal options system.
|
||||
|
||||
name = preset
|
||||
file = libplacebo
|
||||
directory = Video/libplacebo
|
||||
default = default
|
||||
help = Override all libplacebo options by the values from the given preset.
|
||||
url = https://libplacebo.org/options/#presetdefaultfasthigh_quality
|
||||
option = default Default settings, tuned to provide a balance of performance and quality.
|
||||
option = fast Disable all advanced rendering, equivalent to passing no to every option.
|
||||
option = high_quality Reset all everything to high quality presets (where available).
|
||||
|
||||
name = upscaler
|
||||
file = libplacebo
|
||||
directory = Video/libplacebo/Scaling
|
||||
default = lanczos
|
||||
help = Sets the filter used for upscaling.
|
||||
url = https://libplacebo.org/options/#upscalerfilter
|
||||
option-name-width = 135
|
||||
option = none No filter, only use basic GPU texture sampling.
|
||||
option = nearest Nearest-neighbour (box) sampling (very fast).
|
||||
option = bilinear Bilinear sampling (very fast).
|
||||
option = oversample Aspect-ratio preserving nearest neighbour sampling (very fast).
|
||||
option = bicubic Bicubic interpolation (fast).
|
||||
option = gaussian Gaussian smoothing (fast).
|
||||
option = catmull_rom Catmull-Rom cubic spline.
|
||||
option = lanczos Lanczos reconstruction.
|
||||
option = ewa_lanczos EWA Lanczos ("Jinc") reconstruction (slow).
|
||||
option = ewa_lanczossharp Sharpened version of ewa_lanczos (slow).
|
||||
option = ewa_lanczos4sharpest Very sharp version of ewa_lanczos, with anti-ringing (very slow).
|
||||
|
||||
name = downscaler
|
||||
file = libplacebo
|
||||
directory = Video/libplacebo/Scaling
|
||||
default = hermite
|
||||
help = Sets the filter used for downscaling. The most relevant options, roughly ordered from fastest to slowest.
|
||||
option = none Use the same filter as specified for upscaler
|
||||
option = box Box averaging (very fast)
|
||||
option = hermite Hermite-weighted averaging (fast)
|
||||
option = bilinear Bilinear (triangle) averaging (fast)
|
||||
option = bicubic Bicubic interpolation (fast)
|
||||
option = gaussian Gaussian smoothing (fast)
|
||||
option = catmull_rom Catmull-Rom cubic spline
|
||||
option = mitchell Mitchell-Netravalia cubic spline
|
||||
option = lanczos Lanczos reconstruction
|
||||
|
||||
name = plane_upscaler
|
||||
file = libplacebo
|
||||
directory = Video/libplacebo/Scaling
|
||||
default = none
|
||||
help = Override the filter used for upscaling planes, e.g. chroma/alpha. If set to none, use the same setting as upscaler, respectively.
|
||||
option = none Use the same filter as specified for upscaler
|
||||
option = box Box averaging (very fast)
|
||||
option = hermite Hermite-weighted averaging (fast)
|
||||
option = bilinear Bilinear (triangle) averaging (fast)
|
||||
option = bicubic Bicubic interpolation (fast)
|
||||
option = gaussian Gaussian smoothing (fast)
|
||||
option = catmull_rom Catmull-Rom cubic spline
|
||||
option = mitchell Mitchell-Netravalia cubic spline
|
||||
option = lanczos Lanczos reconstruction
|
||||
|
||||
name = plane_downscaler
|
||||
file = libplacebo
|
||||
directory = Video/libplacebo/Scaling
|
||||
default = none
|
||||
help = Override the filter used for downscaling planes, e.g. chroma/alpha. If set to none, use the same setting as downscaler, respectively.
|
||||
option = none Use the same filter as specified for upscaler
|
||||
option = box Box averaging (very fast)
|
||||
option = hermite Hermite-weighted averaging (fast)
|
||||
option = bilinear Bilinear (triangle) averaging (fast)
|
||||
option = bicubic Bicubic interpolation (fast)
|
||||
option = gaussian Gaussian smoothing (fast)
|
||||
option = catmull_rom Catmull-Rom cubic spline
|
||||
option = mitchell Mitchell-Netravalia cubic spline
|
||||
option = lanczos Lanczos reconstruction
|
||||
|
||||
name = frame_mixer
|
||||
file = libplacebo
|
||||
directory = Video/libplacebo/Scaling
|
||||
default = oversample
|
||||
help = Sets the filter used for frame mixing (temporal interpolation). Roughly ordered from fastest to slowest.
|
||||
option = none Disable frame mixing, show nearest frame to target PTS
|
||||
option = oversample Oversampling, only mix "edge" frames while preserving FPS
|
||||
option = hermite Hermite-weighted frame mixing
|
||||
option = linear Linear frame mixing
|
||||
option = cubic Cubic B-spline frame mixing
|
||||
|
||||
name = antiringing_strength
|
||||
file = libplacebo
|
||||
directory = Video/libplacebo/Scaling
|
||||
help = <0.0..1.0> Antiringing strength to use for all filters. A value of 0.0 disables antiringing, and a value of 1.0 enables full-strength antiringing. Defaults to 0.0.
|
||||
|
||||
name = deband
|
||||
file = libplacebo
|
||||
directory = Video/libplacebo/Debanding
|
||||
help = Enables debanding using libplacebo.
|
||||
default = no
|
||||
option = yes
|
||||
option = no
|
||||
|
||||
name = deband_iterations
|
||||
file = libplacebo
|
||||
directory = Video/libplacebo/Debanding
|
||||
help = <0..16> The number of debanding steps to perform per sample. Each step reduces a bit more banding, but takes time to compute. Note that the strength of each step falls off very quickly, so high numbers (>4) are practically useless. Defaults to 1.
|
||||
|
||||
name = deband_threshold
|
||||
file = libplacebo
|
||||
directory = Video/libplacebo/Debanding
|
||||
help = <0.0..1000.0> The debanding filter's cut-off threshold. Higher numbers increase the debanding strength dramatically, but progressively diminish image details. Defaults to 3.0.
|
||||
|
||||
name = deband_radius
|
||||
file = libplacebo
|
||||
directory = Video/libplacebo/Debanding
|
||||
help = <0.0..1000.0> The debanding filter's initial radius. The radius increases linearly for each iteration. A higher radius will find more gradients, but a lower radius will smooth more aggressively. Defaults to 16.0.
|
||||
|
||||
name = deband_grain
|
||||
file = libplacebo
|
||||
directory = Video/libplacebo/Debanding
|
||||
help = <0.0..1000.0> Add some extra noise to the image. This significantly helps cover up remaining quantization artifacts. Higher numbers add more noise. Defaults to 4.0, which is very mild.
|
||||
|
||||
name = sigmoid
|
||||
file = libplacebo
|
||||
directory = Video/libplacebo/Sigmoidization
|
||||
help = Enables sigmoidization.
|
||||
default = yes
|
||||
option = yes
|
||||
option = no
|
||||
|
||||
name = sigmoid_center
|
||||
file = libplacebo
|
||||
directory = Video/libplacebo/Sigmoidization
|
||||
help = <0.0..1.0> The center (bias) of the sigmoid curve. Defaults to 0.75.
|
||||
|
||||
name = sigmoid_slope
|
||||
file = libplacebo
|
||||
directory = Video/libplacebo/Sigmoidization
|
||||
help = <1.0..20.0> The slope (steepness) of the sigmoid curve. Defaults to 6.5.
|
||||
|
||||
name = screenshot-directory
|
||||
file = mpv
|
||||
width = 500
|
||||
type = folder
|
||||
directory = Video/Screenshot
|
||||
help = 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.
|
||||
|
||||
name = screenshot-format
|
||||
file = mpv
|
||||
default = jpg
|
||||
directory = Video/Screenshot
|
||||
help = Set the image file type used for saving screenshots.
|
||||
option = jpg
|
||||
option = png
|
||||
|
||||
name = screenshot-tag-colorspace
|
||||
file = mpv
|
||||
default = no
|
||||
directory = Video/Screenshot
|
||||
help = Tag screenshots with the appropriate colorspace. Note that not all formats are supported.
|
||||
option = yes
|
||||
option = no
|
||||
|
||||
name = screenshot-high-bit-depth
|
||||
file = mpv
|
||||
default = yes
|
||||
directory = Video/Screenshot
|
||||
help = If possible, write screenshots with a bit depth similar to the source video. This is interesting in particular for PNG, as this sometimes triggers writing 16 bit PNGs with huge file sizes. This will also include an unused alpha channel in the resulting files if 16 bit is used.
|
||||
option = yes
|
||||
option = no
|
||||
|
||||
name = screenshot-jpeg-source-chroma
|
||||
file = mpv
|
||||
default = yes
|
||||
directory = Video/Screenshot
|
||||
help = Write JPEG files with the same chroma subsampling as the video. If disabled, the libjpeg default is used.
|
||||
option = yes
|
||||
option = no
|
||||
|
||||
name = screenshot-template
|
||||
file = mpv
|
||||
directory = Video/Screenshot
|
||||
type = string
|
||||
help = Specify the filename template used to save screenshots. The template specifies the filename without file extension, and can contain format specifiers, which will be substituted when taking a screenshot. By default, the template is mpv-shot%n, which results in filenames like mpv-shot0012.png for example.\n\nFind the full documentation here:
|
||||
url = https://mpv.io/manual/master/#options-screenshot-template
|
||||
|
||||
name = screenshot-jpeg-quality
|
||||
file = mpv
|
||||
directory = Video/Screenshot
|
||||
help = <0-100> Set the JPEG quality level. Higher means better quality. The default is 90.
|
||||
|
||||
name = screenshot-png-compression
|
||||
file = mpv
|
||||
directory = Video/Screenshot
|
||||
help = <0-9> Set the PNG compression level. Higher means better compression. This will affect the file size of the written screenshot file and the time it takes to write a screenshot. Too high compression might occupy enough CPU time to interrupt playback. The default is 7.
|
||||
|
||||
name = screenshot-png-filter
|
||||
file = mpv
|
||||
directory = Video/Screenshot
|
||||
help = <0-5> Set the filter applied prior to PNG compression. 0 is none, 1 is 'sub', 2 is 'up', 3 is 'average', 4 is 'Paeth', and 5 is 'mixed'. This affects the level of compression that can be achieved. For most images, 'mixed' achieves the best compression ratio, hence it is the default.
|
||||
|
||||
name = volume
|
||||
file = mpv
|
||||
directory = Audio
|
||||
@@ -228,7 +443,7 @@ name = alang
|
||||
file = mpv
|
||||
directory = Audio
|
||||
type = string
|
||||
help = 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.
|
||||
help = 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.
|
||||
|
||||
name = audio-file-auto
|
||||
file = mpv
|
||||
@@ -293,10 +508,16 @@ type = color
|
||||
directory = Subtitle
|
||||
help = See sub-color. Color used for sub text background. You can use sub-shadow-offset to change its size relative to the text.
|
||||
|
||||
name = title
|
||||
file = mpv
|
||||
directory = Window
|
||||
width = 400
|
||||
help = Set the window title. This is used for the video window, and if possible, also sets the audio stream title. Properties are expanded. Warning! There is a danger of this causing significant CPU usage, depending on the properties used.
|
||||
|
||||
name = fullscreen
|
||||
file = mpv
|
||||
default = no
|
||||
directory = Screen
|
||||
directory = Window
|
||||
help = Start the player in fullscreen mode.
|
||||
option = yes
|
||||
option = no
|
||||
@@ -304,71 +525,84 @@ option = no
|
||||
name = border
|
||||
file = mpv
|
||||
default = yes
|
||||
directory = Screen
|
||||
directory = Window
|
||||
help = Show window with decoration (titlebar, border).
|
||||
option = yes
|
||||
option = no
|
||||
|
||||
name = screen
|
||||
file = mpv
|
||||
directory = Screen
|
||||
directory = Window
|
||||
help = <0-32> In multi-monitor configurations (i.e. a single desktop that spans across multiple displays), this option tells mpv which screen to display the video on.
|
||||
|
||||
name = taskbar-progress
|
||||
file = mpv
|
||||
default = yes
|
||||
directory = Window
|
||||
help = Show progress in taskbar.
|
||||
option = yes
|
||||
option = no
|
||||
|
||||
name = osd-playing-msg
|
||||
file = mpv
|
||||
width = 300
|
||||
directory = Screen
|
||||
directory = Window
|
||||
type = string
|
||||
help = 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:
|
||||
url = https://mpv.io/manual/master/#property-expansion
|
||||
|
||||
name = osd-font-size
|
||||
file = mpv
|
||||
directory = Screen
|
||||
directory = Window
|
||||
help = Specify the OSD font size. See sub-font-size for details. Default: 55
|
||||
|
||||
name = osd-duration
|
||||
file = mpv
|
||||
directory = Screen
|
||||
directory = Window
|
||||
help = Set the duration of the OSD messages in ms. Default: 1000
|
||||
|
||||
name = osd-scale-by-window
|
||||
file = mpv
|
||||
default = yes
|
||||
directory = Screen
|
||||
directory = Window
|
||||
help = Whether to scale the OSD with the window size. If this is disabled, osd-font-size and other OSD options that use scaled pixels are always in actual pixels. The effect is that changing the window size won't change the OSD font size.
|
||||
option = yes
|
||||
option = no
|
||||
|
||||
name = autofit
|
||||
file = mpv
|
||||
directory = Screen
|
||||
directory = Window
|
||||
help = <int> Initial window height in percent. Default: 60
|
||||
|
||||
name = autofit-image
|
||||
file = mpvnet
|
||||
directory = Screen
|
||||
help = <int> Initial window height in percent for image files. Default: 80
|
||||
|
||||
name = autofit-audio
|
||||
file = mpvnet
|
||||
directory = Screen
|
||||
help = <int> Initial window height in percent for audio files. Default: 70
|
||||
|
||||
name = autofit-smaller
|
||||
file = mpv
|
||||
directory = Screen
|
||||
directory = Window
|
||||
help = <int> Minimum window height in percent. Default: 10
|
||||
|
||||
name = autofit-larger
|
||||
file = mpv
|
||||
directory = Screen
|
||||
directory = Window
|
||||
help = <int> Maximum window height in percent. Default: 80
|
||||
|
||||
name = autofit-image
|
||||
file = mpvnet
|
||||
directory = Window
|
||||
help = <int> Initial window height in percent for image files. Default: 80
|
||||
|
||||
name = autofit-audio
|
||||
file = mpvnet
|
||||
directory = Window
|
||||
help = <int> Initial window height in percent for audio files. Default: 70
|
||||
|
||||
name = geometry
|
||||
file = mpvnet
|
||||
directory = Window
|
||||
help = <x:y> Initial window location in percent. Default: 50:50 (centered)\n\nx=0 docks the window to the left side.\nx=100 docks the window to the right side.\ny=0 docks the window to the top side.\ny=100 docks the window to the bottom side.
|
||||
|
||||
name = start-size
|
||||
file = mpvnet
|
||||
default = height-session
|
||||
directory = Screen
|
||||
directory = Window
|
||||
help = Setting to remember the window size. (mpv.net option)
|
||||
option = width-session Window width is remembered in the current session
|
||||
option = width-always Window width is always remembered
|
||||
@@ -381,25 +615,25 @@ option = always Window size is always remembered
|
||||
name = keepaspect-window
|
||||
file = mpv
|
||||
default = yes
|
||||
directory = Screen
|
||||
directory = Window
|
||||
help = keepaspect-window will lock the window size to the video aspect. Default: yes
|
||||
option = yes
|
||||
option = no
|
||||
|
||||
name = minimum-aspect-ratio
|
||||
file = mpvnet
|
||||
directory = Screen
|
||||
directory = Window
|
||||
help = <float> Minimum aspect ratio of the window. Useful to force a wider window and therefore a larger OSC. (mpv.net option)
|
||||
|
||||
name = minimum-aspect-ratio-audio
|
||||
file = mpvnet
|
||||
directory = Screen
|
||||
directory = Window
|
||||
help = Same as minimum-aspect-ratio but used for audio files.
|
||||
|
||||
name = remember-window-position
|
||||
file = mpvnet
|
||||
default = no
|
||||
directory = Screen
|
||||
directory = Window
|
||||
help = Save the window position on exit. (mpv.net option)
|
||||
option = yes
|
||||
option = no
|
||||
@@ -407,7 +641,7 @@ option = no
|
||||
name = snap-window
|
||||
file = mpv
|
||||
default = no
|
||||
directory = Screen
|
||||
directory = Window
|
||||
help = Snap the player window to screen edges.
|
||||
option = yes
|
||||
option = no
|
||||
@@ -415,24 +649,11 @@ option = no
|
||||
name = window-maximized
|
||||
file = mpv
|
||||
default = no
|
||||
directory = Screen
|
||||
directory = Window
|
||||
help = Start with a maximized window.
|
||||
option = yes
|
||||
option = no
|
||||
|
||||
name = start-threshold
|
||||
file = mpvnet
|
||||
directory = Screen
|
||||
help = Threshold in milliseconds to wait for libmpv returning the video resolution before the window is shown, otherwise default dimensions are used as defined by autofit and start-size. Default: 1500 (mpv.net option)
|
||||
|
||||
name = taskbar-progress
|
||||
file = mpv
|
||||
default = yes
|
||||
directory = Playback
|
||||
help = Show progress in taskbar.
|
||||
option = yes
|
||||
option = no
|
||||
|
||||
name = keep-open
|
||||
file = mpv
|
||||
default = no
|
||||
@@ -508,6 +729,12 @@ help = For single files automatically load the entire directory into the playlis
|
||||
option = yes
|
||||
option = no
|
||||
|
||||
name = reset-on-next-file
|
||||
file = mpv
|
||||
directory = Program Behavior
|
||||
help = Normally, mpv will try to keep all settings when playing the next file on the playlist, even if they were changed by the user during playback. This can be changed with this option. It accepts a list of options, and mpv will reset the value of these options on playback start to the initial value.
|
||||
width = 400
|
||||
|
||||
name = input-ar-delay
|
||||
file = mpv
|
||||
directory = Input
|
||||
@@ -518,6 +745,12 @@ file = mpv
|
||||
directory = Input
|
||||
help = Number of key presses to generate per second on autorepeat.
|
||||
|
||||
name = input-ipc-server
|
||||
file = mpv
|
||||
directory = Input
|
||||
help = Enable the IPC support and create the listening socket at the given path.
|
||||
url = https://mpv.io/manual/master/#options-input-ipc-server
|
||||
|
||||
name = language
|
||||
file = mpvnet
|
||||
default = system
|
||||
@@ -550,67 +783,6 @@ directory = UI
|
||||
url = https://github.com/mpvnet-player/mpv.net/blob/main/docs/manual.md#color-theme
|
||||
help = Color theme used in light mode.\nmpv.net must be restarted after a change.\nmpv.net specific option. Default: light
|
||||
|
||||
name = screenshot-directory
|
||||
file = mpv
|
||||
width = 500
|
||||
type = folder
|
||||
directory = Video/Screenshot
|
||||
help = 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.
|
||||
|
||||
name = screenshot-format
|
||||
file = mpv
|
||||
default = jpg
|
||||
directory = Video/Screenshot
|
||||
help = Set the image file type used for saving screenshots.
|
||||
option = jpg
|
||||
option = png
|
||||
|
||||
name = screenshot-tag-colorspace
|
||||
file = mpv
|
||||
default = no
|
||||
directory = Video/Screenshot
|
||||
help = Tag screenshots with the appropriate colorspace. Note that not all formats are supported.
|
||||
option = yes
|
||||
option = no
|
||||
|
||||
name = screenshot-high-bit-depth
|
||||
file = mpv
|
||||
default = yes
|
||||
directory = Video/Screenshot
|
||||
help = If possible, write screenshots with a bit depth similar to the source video. This is interesting in particular for PNG, as this sometimes triggers writing 16 bit PNGs with huge file sizes. This will also include an unused alpha channel in the resulting files if 16 bit is used.
|
||||
option = yes
|
||||
option = no
|
||||
|
||||
name = screenshot-jpeg-source-chroma
|
||||
file = mpv
|
||||
default = yes
|
||||
directory = Video/Screenshot
|
||||
help = Write JPEG files with the same chroma subsampling as the video. If disabled, the libjpeg default is used.
|
||||
option = yes
|
||||
option = no
|
||||
|
||||
name = screenshot-template
|
||||
file = mpv
|
||||
directory = Video/Screenshot
|
||||
type = string
|
||||
help = Specify the filename template used to save screenshots. The template specifies the filename without file extension, and can contain format specifiers, which will be substituted when taking a screenshot. By default, the template is mpv-shot%n, which results in filenames like mpv-shot0012.png for example.\n\nFind the full documentation here:
|
||||
url = https://mpv.io/manual/master/#options-screenshot-template
|
||||
|
||||
name = screenshot-jpeg-quality
|
||||
file = mpv
|
||||
directory = Video/Screenshot
|
||||
help = <0-100> Set the JPEG quality level. Higher means better quality. The default is 90.
|
||||
|
||||
name = screenshot-png-compression
|
||||
file = mpv
|
||||
directory = Video/Screenshot
|
||||
help = <0-9> Set the PNG compression level. Higher means better compression. This will affect the file size of the written screenshot file and the time it takes to write a screenshot. Too high compression might occupy enough CPU time to interrupt playback. The default is 7.
|
||||
|
||||
name = screenshot-png-filter
|
||||
file = mpv
|
||||
directory = Video/Screenshot
|
||||
help = <0-5> Set the filter applied prior to PNG compression. 0 is none, 1 is 'sub', 2 is 'up', 3 is 'average', 4 is 'Paeth', and 5 is 'mixed'. This affects the level of compression that can be achieved. For most images, 'mixed' achieves the best compression ratio, hence it is the default.
|
||||
|
||||
name = cache
|
||||
file = mpv
|
||||
default = auto
|
||||
|
||||
@@ -16,6 +16,7 @@ public abstract class Setting
|
||||
public string? Value { get; set; }
|
||||
|
||||
public int Width { get; set; }
|
||||
public int OptionNameWidth { get; set; } = 100;
|
||||
|
||||
public ConfItem? ConfItem { get; set; }
|
||||
}
|
||||
@@ -35,12 +36,13 @@ public class OptionSettingOption
|
||||
|
||||
public string? Name { get; set; }
|
||||
public string? Help { get; set; }
|
||||
public int OptionWidth { get => OptionSetting!.OptionNameWidth; }
|
||||
|
||||
public OptionSetting? OptionSetting { get; set; }
|
||||
|
||||
public string? Text
|
||||
{
|
||||
get => string.IsNullOrEmpty(_text) ? Name : _text;
|
||||
get => _text ?? Name;
|
||||
set => _text = value;
|
||||
}
|
||||
|
||||
|
||||
18
src/MpvNet.Windows/WPF/ComboBoxTemplateSelector.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
using System.Windows.Controls;
|
||||
using System.Windows;
|
||||
|
||||
namespace MpvNet.Windows.WPF;
|
||||
|
||||
public class ComboBoxTemplateSelector : DataTemplateSelector
|
||||
{
|
||||
public override DataTemplate SelectTemplate(object item, DependencyObject container)
|
||||
{
|
||||
ContentPresenter presenter = (ContentPresenter)container;
|
||||
|
||||
if (presenter.TemplatedParent is ComboBox)
|
||||
return (DataTemplate)presenter.FindResource("ComboBoxCollapsedDataTemplate");
|
||||
else // Templated parent is ComboBoxItem
|
||||
return (DataTemplate)presenter.FindResource("ComboBoxExpandedDataTemplate");
|
||||
}
|
||||
}
|
||||
@@ -28,8 +28,8 @@
|
||||
<KeyBinding Key="n" Modifiers="Ctrl" Command="{Binding ShowMpvNetSpecificSettingsCommand}"/>
|
||||
<KeyBinding Key="F5" Command="{Binding PreviewMpvConfFileCommand}"/>
|
||||
<KeyBinding Key="F6" Command="{Binding PreviewMpvNetConfFileCommand}"/>
|
||||
<KeyBinding Key="F1" Command="{Binding ShowMpvManualCommand}"/>
|
||||
<KeyBinding Key="F2" Command="{Binding ShowMpvNetManualCommand}"/>
|
||||
<KeyBinding Key="F1" Modifiers="Ctrl" Command="{Binding ShowMpvManualCommand}"/>
|
||||
<KeyBinding Key="F2" Modifiers="Ctrl" Command="{Binding ShowMpvNetManualCommand}"/>
|
||||
</Window.InputBindings>
|
||||
|
||||
<Grid>
|
||||
@@ -40,7 +40,7 @@
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="170" />
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
@@ -135,12 +135,12 @@
|
||||
<Separator />
|
||||
<MenuItem
|
||||
Header="Show mpv manual"
|
||||
InputGestureText="F1"
|
||||
InputGestureText="Ctrl+F1"
|
||||
Command="{Binding Data.ShowMpvManualCommand, Source={StaticResource BindingProxy}}"
|
||||
/>
|
||||
<MenuItem
|
||||
Header="Show mpv.net manual"
|
||||
InputGestureText="F2"
|
||||
InputGestureText="Ctrl+F2"
|
||||
Command="{Binding Data.ShowMpvNetManualCommand, Source={StaticResource BindingProxy}}"
|
||||
/>
|
||||
</ContextMenu>
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
@@ -34,19 +35,20 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
|
||||
DataContext = this;
|
||||
LoadConf(Player.ConfPath);
|
||||
LoadConf(App.ConfPath);
|
||||
LoadLibplaceboConf();
|
||||
LoadSettings();
|
||||
InitialContent = GetCompareString();
|
||||
|
||||
if (string.IsNullOrEmpty(App.Settings.ConfigEditorSearch))
|
||||
SearchControl.Text = "General:";
|
||||
SearchText = "General:";
|
||||
else
|
||||
SearchControl.Text = App.Settings.ConfigEditorSearch;
|
||||
SearchText = App.Settings.ConfigEditorSearch;
|
||||
|
||||
foreach (var node in Nodes)
|
||||
SelectNodeFromSearchText(node);
|
||||
|
||||
foreach (var node in Nodes)
|
||||
ExpandNode(node);
|
||||
node.IsExpanded = true;
|
||||
}
|
||||
|
||||
public Theme? Theme => Theme.Current;
|
||||
@@ -82,6 +84,9 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
|
||||
|
||||
public static TreeNode? AddNode(IList<TreeNode> nodes, string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
return null;
|
||||
|
||||
string[] parts = path.Split('/', StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
for (int x = 0; x < parts.Length; x++)
|
||||
@@ -127,14 +132,16 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
|
||||
if (!FilterStrings.Contains(setting.Directory!))
|
||||
FilterStrings.Add(setting.Directory!);
|
||||
|
||||
foreach (ConfItem confItem in ConfItems)
|
||||
foreach (ConfItem item in ConfItems)
|
||||
{
|
||||
if (setting.Name == confItem.Name && confItem.Section == "" && !confItem.IsSectionItem)
|
||||
if (setting.Name == item.Name &&
|
||||
setting.File == item.File &&
|
||||
item.Section == "" && !item.IsSectionItem)
|
||||
{
|
||||
setting.Value = confItem.Value.Trim('\'', '"');
|
||||
setting.Value = item.Value;
|
||||
setting.StartValue = setting.Value;
|
||||
setting.ConfItem = confItem;
|
||||
confItem.SettingBase = setting;
|
||||
setting.ConfItem = item;
|
||||
item.SettingBase = setting;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,6 +151,9 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
|
||||
MainStackPanel.Children.Add(new StringSettingControl(s) { Visibility = Visibility.Collapsed });
|
||||
break;
|
||||
case OptionSetting s:
|
||||
if (s.Options.Count > 3)
|
||||
MainStackPanel.Children.Add(new ComboBoxSettingControl(s) { Visibility = Visibility.Collapsed });
|
||||
else
|
||||
MainStackPanel.Children.Add(new OptionSettingControl(s) { Visibility = Visibility.Collapsed });
|
||||
break;
|
||||
}
|
||||
@@ -155,11 +165,20 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
|
||||
protected override void OnClosed(EventArgs e)
|
||||
{
|
||||
base.OnClosed(e);
|
||||
App.Settings.ConfigEditorSearch = SearchControl.Text;
|
||||
App.Settings.ConfigEditorSearch = SearchText;
|
||||
|
||||
if (InitialContent == GetCompareString())
|
||||
return;
|
||||
|
||||
foreach (Setting setting in Settings)
|
||||
{
|
||||
if (setting.Name == "libplacebo-opts")
|
||||
{
|
||||
setting.Value = GetKeyValueContent("libplacebo");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
File.WriteAllText(Player.ConfPath, GetContent("mpv"));
|
||||
File.WriteAllText(App.ConfPath, GetContent("mpvnet"));
|
||||
|
||||
@@ -201,10 +220,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
|
||||
DispatcherPriority.Background);
|
||||
}
|
||||
|
||||
string GetCompareString()
|
||||
{
|
||||
return string.Join("", Settings.Select(item => item.Name + item.Value).ToArray());
|
||||
}
|
||||
string GetCompareString() => string.Join("", Settings.Select(item => item.Name + item.Value).ToArray());
|
||||
|
||||
void LoadConf(string file)
|
||||
{
|
||||
@@ -221,14 +237,10 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
|
||||
string line = currentLine.Trim();
|
||||
|
||||
if (line == "")
|
||||
{
|
||||
comment += "\r\n";
|
||||
}
|
||||
else if (line.StartsWith("#"))
|
||||
{
|
||||
comment += line.Trim() + "\r\n";
|
||||
}
|
||||
else if (line.StartsWith("[") && line.Contains("]"))
|
||||
else if (line.StartsWith("[") && line.Contains(']'))
|
||||
{
|
||||
if (!isSectionItem && comment != "" && comment != "\r\n")
|
||||
ConfItems.Add(new ConfItem() {
|
||||
@@ -238,9 +250,12 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
|
||||
comment = "";
|
||||
isSectionItem = true;
|
||||
}
|
||||
else if (line.Contains("="))
|
||||
else if (line.Contains('=') || Regex.Match(line, "^[\\w-]+$").Success)
|
||||
{
|
||||
ConfItem item = new ConfItem();
|
||||
if (!line.Contains('='))
|
||||
line += "=yes";
|
||||
|
||||
ConfItem item = new();
|
||||
item.File = Path.GetFileNameWithoutExtension(file);
|
||||
item.IsSectionItem = isSectionItem;
|
||||
item.Comment = comment;
|
||||
@@ -248,16 +263,22 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
|
||||
item.Section = section;
|
||||
section = "";
|
||||
|
||||
if (line.Contains("#") && !line.Contains("'") && !line.Contains("\""))
|
||||
if (line.Contains('#') && !line.Contains("'") && !line.Contains("\""))
|
||||
{
|
||||
item.LineComment = line.Substring(line.IndexOf("#")).Trim();
|
||||
line = line.Substring(0, line.IndexOf("#")).Trim();
|
||||
}
|
||||
|
||||
int pos = line.IndexOf("=");
|
||||
string left = line.Substring(0, pos).Trim().ToLower();
|
||||
string left = line.Substring(0, pos).Trim().ToLower().TrimStart('-');
|
||||
string right = line.Substring(pos + 1).Trim();
|
||||
|
||||
if (right.StartsWith('\'') && right.EndsWith('\''))
|
||||
right = right.Trim('\'');
|
||||
|
||||
if (right.StartsWith('"') && right.EndsWith('"'))
|
||||
right = right.Trim('"');
|
||||
|
||||
if (left == "fs")
|
||||
left = "fullscreen";
|
||||
|
||||
@@ -271,6 +292,67 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
|
||||
}
|
||||
}
|
||||
|
||||
string GetKeyValueContent(string filename)
|
||||
{
|
||||
List<string> pairs = new();
|
||||
|
||||
foreach (Setting setting in Settings)
|
||||
{
|
||||
if (filename != setting.File)
|
||||
continue;
|
||||
|
||||
if ((setting.Value ?? "") != setting.Default)
|
||||
pairs.Add(setting.Name + "=" + EscapeValue(setting.Value!));
|
||||
}
|
||||
|
||||
return string.Join(',', pairs);
|
||||
}
|
||||
|
||||
void LoadLibplaceboConf()
|
||||
{
|
||||
foreach (ConfItem item in ConfItems.ToArray())
|
||||
if (item.Name == "libplacebo-opts")
|
||||
LoadKeyValueList(item.Value, "libplacebo");
|
||||
}
|
||||
|
||||
void LoadKeyValueList(string options, string file)
|
||||
{
|
||||
string[] optionStrings = options.Split(",", StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
foreach (string pair in optionStrings)
|
||||
{
|
||||
if (!pair.Contains('='))
|
||||
continue;
|
||||
|
||||
int pos = pair.IndexOf("=");
|
||||
string left = pair.Substring(0, pos).Trim().ToLower();
|
||||
string right = pair.Substring(pos + 1).Trim();
|
||||
|
||||
ConfItem item = new();
|
||||
item.Name = left;
|
||||
item.Value = right;
|
||||
item.File = file;
|
||||
ConfItems.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
string EscapeValue(string value)
|
||||
{
|
||||
if (value.Contains('\''))
|
||||
return '"' + value + '"';
|
||||
|
||||
if (value.Contains('"'))
|
||||
return '\'' + value + '\'';
|
||||
|
||||
if (value.Contains('"') || value.Contains('#') || value.StartsWith("%") ||
|
||||
value.StartsWith(" ") || value.EndsWith(" "))
|
||||
{
|
||||
return '\'' + value + '\'';
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
string GetContent(string filename)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
@@ -288,7 +370,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
|
||||
{
|
||||
if (item.Name != "")
|
||||
{
|
||||
sb.Append(item.Name + " = " + item.Value);
|
||||
sb.Append(item.Name + " = " + EscapeValue(item.Value));
|
||||
|
||||
if (item.LineComment != "")
|
||||
sb.Append(" " + item.LineComment);
|
||||
@@ -299,17 +381,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
|
||||
}
|
||||
else if ((item.SettingBase.Value ?? "") != item.SettingBase.Default)
|
||||
{
|
||||
string? value;
|
||||
|
||||
if (item.SettingBase.Type == "string" ||
|
||||
item.SettingBase.Type == "folder" ||
|
||||
item.SettingBase.Type == "color")
|
||||
|
||||
value = "'" + item.SettingBase.Value + "'";
|
||||
else
|
||||
value = item.SettingBase.Value;
|
||||
|
||||
sb.Append(item.Name + " = " + value);
|
||||
sb.Append(item.Name + " = " + EscapeValue(item.SettingBase.Value!));
|
||||
|
||||
if (item.LineComment != "")
|
||||
sb.Append(" " + item.LineComment);
|
||||
@@ -319,28 +391,13 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
|
||||
}
|
||||
}
|
||||
|
||||
if (!sb.ToString().Contains("# Editor"))
|
||||
sb.AppendLine("# Editor");
|
||||
|
||||
foreach (Setting setting in Settings)
|
||||
{
|
||||
if (filename != setting.File || namesWritten.Contains(setting.Name!))
|
||||
continue;
|
||||
|
||||
if ((setting.Value ?? "") != setting.Default)
|
||||
{
|
||||
string? value;
|
||||
|
||||
if (setting.Type == "string" ||
|
||||
setting.Type == "folder" ||
|
||||
setting.Type == "color")
|
||||
|
||||
value = "'" + setting.Value + "'";
|
||||
else
|
||||
value = setting.Value;
|
||||
|
||||
sb.AppendLine(setting.Name + " = " + value);
|
||||
}
|
||||
sb.AppendLine(setting.Name + " = " + EscapeValue(setting.Value!));
|
||||
}
|
||||
|
||||
foreach (ConfItem item in ConfItems)
|
||||
@@ -359,7 +416,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
|
||||
if (item.Comment != "")
|
||||
sb.Append(item.Comment);
|
||||
|
||||
sb.Append(item.Name + " = " + item.Value);
|
||||
sb.Append(item.Name + " = " + EscapeValue(item.Value));
|
||||
|
||||
if (item.LineComment != "")
|
||||
sb.Append(" " + item.LineComment);
|
||||
@@ -443,9 +500,10 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
|
||||
|
||||
void SelectNodeFromSearchText(NodeViewModel node)
|
||||
{
|
||||
if (node.Path + ":" == SearchControl.Text)
|
||||
if (node.Path + ":" == SearchText)
|
||||
{
|
||||
node.IsSelected = true;
|
||||
node.IsExpanded = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -462,15 +520,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
|
||||
UnselectNode(it);
|
||||
}
|
||||
|
||||
void ExpandNode(NodeViewModel node)
|
||||
{
|
||||
node.IsExpanded = true;
|
||||
|
||||
foreach (var it in node.Children)
|
||||
ExpandNode(it);
|
||||
}
|
||||
|
||||
[RelayCommand] void ShowMpvNetSpecificSettings() => SearchControl.Text = "mpv.net";
|
||||
[RelayCommand] void ShowMpvNetSpecificSettings() => SearchText = "mpv.net";
|
||||
|
||||
[RelayCommand] void PreviewMpvConfFile() => Msg.ShowInfo(GetContent("mpv"));
|
||||
|
||||
|
||||
72
src/MpvNet.Windows/WPF/Controls/ComboBoxSettingControl.xaml
Normal file
@@ -0,0 +1,72 @@
|
||||
<UserControl
|
||||
x:Name="ComboBoxSettingControl1"
|
||||
x:Class="MpvNet.Windows.WPF.ComboBoxSettingControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MpvNet.Windows.WPF"
|
||||
mc:Ignorable="d"
|
||||
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800">
|
||||
|
||||
<Grid Margin="20,0">
|
||||
<StackPanel>
|
||||
<TextBox
|
||||
x:Name="TitleTextBox"
|
||||
FontSize="24"
|
||||
Margin="0,10"
|
||||
BorderThickness="0"
|
||||
IsReadOnly="True"
|
||||
Foreground="{Binding Theme.Heading}"
|
||||
Background="{Binding Theme.Background}"
|
||||
/>
|
||||
|
||||
<ComboBox
|
||||
Name="ComboBoxControl"
|
||||
Width="200"
|
||||
HorizontalAlignment="Left"
|
||||
MaxDropDownHeight="2000"
|
||||
Foreground="{Binding Theme.Foreground}"
|
||||
Background="{Binding Theme.Background}"
|
||||
|
||||
SelectionChanged="ComboBoxControl_SelectionChanged"
|
||||
>
|
||||
<ComboBox.ItemTemplateSelector>
|
||||
<local:ComboBoxTemplateSelector/>
|
||||
</ComboBox.ItemTemplateSelector>
|
||||
|
||||
<ComboBox.ItemContainerStyle>
|
||||
<Style TargetType="ComboBoxItem">
|
||||
<Style.Resources>
|
||||
<Style TargetType="Border">
|
||||
<Setter Property="CornerRadius" Value="3"/>
|
||||
</Style>
|
||||
</Style.Resources>
|
||||
</Style>
|
||||
</ComboBox.ItemContainerStyle>
|
||||
</ComboBox>
|
||||
|
||||
<TextBox
|
||||
x:Name="HelpTextBox"
|
||||
TextWrapping="WrapWithOverflow"
|
||||
BorderThickness="0"
|
||||
IsReadOnly="True"
|
||||
Margin="0,10,0,0"
|
||||
Foreground="{Binding Theme.Foreground}"
|
||||
Background="{Binding Theme.Background}"
|
||||
/>
|
||||
|
||||
<TextBlock
|
||||
x:Name="LinkTextBlock"
|
||||
Margin="2,0"
|
||||
>
|
||||
<local:HyperlinkEx
|
||||
x:Name="Link"
|
||||
Foreground="{Binding Theme.Heading}"
|
||||
/>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,69 @@
|
||||
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
using MpvNet.Windows.UI;
|
||||
|
||||
namespace MpvNet.Windows.WPF;
|
||||
|
||||
public partial class ComboBoxSettingControl : UserControl, ISettingControl
|
||||
{
|
||||
OptionSetting OptionSetting;
|
||||
|
||||
public ComboBoxSettingControl(OptionSetting optionSetting)
|
||||
{
|
||||
OptionSetting = optionSetting;
|
||||
InitializeComponent();
|
||||
DataContext = this;
|
||||
TitleTextBox.Text = optionSetting.Name;
|
||||
|
||||
if (string.IsNullOrEmpty(optionSetting.Help))
|
||||
HelpTextBox.Visibility = Visibility.Collapsed;
|
||||
|
||||
HelpTextBox.Text = optionSetting.Help;
|
||||
ComboBoxControl.ItemsSource = optionSetting.Options;
|
||||
|
||||
foreach (var item in optionSetting.Options)
|
||||
if (item.Name == optionSetting.Value)
|
||||
ComboBoxControl.SelectedItem = item;
|
||||
|
||||
if (string.IsNullOrEmpty(optionSetting.URL))
|
||||
LinkTextBlock.Visibility = Visibility.Collapsed;
|
||||
|
||||
Link.SetURL(optionSetting.URL);
|
||||
}
|
||||
|
||||
public Theme? Theme => Theme.Current;
|
||||
|
||||
public Setting Setting => OptionSetting;
|
||||
|
||||
public bool Contains(string searchString) => ContainsInternal(searchString.ToLower());
|
||||
|
||||
public bool ContainsInternal(string search)
|
||||
{
|
||||
if (TitleTextBox.Text.IndexOf(search, StringComparison.InvariantCultureIgnoreCase) > -1)
|
||||
return true;
|
||||
|
||||
if (HelpTextBox.Text.IndexOf(search, StringComparison.InvariantCultureIgnoreCase) > -1)
|
||||
return true;
|
||||
|
||||
foreach (var i in OptionSetting.Options)
|
||||
{
|
||||
if (i.Text?.IndexOf(search, StringComparison.InvariantCultureIgnoreCase) > -1)
|
||||
return true;
|
||||
|
||||
if (i.Help?.IndexOf(search, StringComparison.InvariantCultureIgnoreCase) > -1)
|
||||
return true;
|
||||
|
||||
if (i.Name?.IndexOf(search, StringComparison.InvariantCultureIgnoreCase) > -1)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ComboBoxControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
OptionSetting.Value = (ComboBoxControl.SelectedItem as OptionSettingOption)?.Name;
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ using System.Windows.Navigation;
|
||||
|
||||
using MpvNet.Help;
|
||||
|
||||
// TODO: change namespace to MpvNet.Windows.WPF.Controls
|
||||
namespace MpvNet.Windows.WPF;
|
||||
|
||||
public class HyperlinkEx : Hyperlink
|
||||
@@ -20,6 +19,6 @@ public class HyperlinkEx : Hyperlink
|
||||
NavigateUri = new Uri(url);
|
||||
RequestNavigate += HyperLinkEx_RequestNavigate;
|
||||
Inlines.Clear();
|
||||
Inlines.Add(url);
|
||||
Inlines.Add("Manual");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,8 +66,14 @@
|
||||
Background="{Binding Theme.Background}"
|
||||
/>
|
||||
|
||||
<TextBlock x:Name="LinkTextBlock" Margin="0,10">
|
||||
<local:HyperlinkEx x:Name="Link"></local:HyperlinkEx>
|
||||
<TextBlock
|
||||
x:Name="LinkTextBlock"
|
||||
Margin="2,0,0,0"
|
||||
>
|
||||
<local:HyperlinkEx
|
||||
x:Name="Link"
|
||||
Foreground="{Binding Theme.Heading}"
|
||||
/>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
@@ -21,6 +21,10 @@ public partial class OptionSettingControl : UserControl, ISettingControl
|
||||
HelpTextBox.Visibility = Visibility.Collapsed;
|
||||
|
||||
HelpTextBox.Text = optionSetting.Help;
|
||||
|
||||
if (string.IsNullOrEmpty(optionSetting.Help))
|
||||
LinkTextBlock.Margin = new Thickness(2, 6, 0, 0);
|
||||
|
||||
ItemsControl.ItemsSource = optionSetting.Options;
|
||||
|
||||
if (string.IsNullOrEmpty(optionSetting.URL))
|
||||
|
||||
@@ -39,7 +39,7 @@ public partial class SearchControl : UserControl
|
||||
{
|
||||
HintTextBlock.Text = string.IsNullOrEmpty(Text) ? HintText : "";
|
||||
|
||||
if (string.IsNullOrEmpty(Text) || HideClearButton)
|
||||
if (string.IsNullOrEmpty(Text) || HideClearButton || Text.Length > 21)
|
||||
SearchClearButton.Visibility = Visibility.Hidden;
|
||||
else
|
||||
SearchClearButton.Visibility = Visibility.Visible;
|
||||
|
||||
@@ -60,8 +60,14 @@
|
||||
Background="{Binding Theme.Background}"
|
||||
/>
|
||||
|
||||
<TextBlock x:Name="LinkTextBlock" Margin="0,10">
|
||||
<local:HyperlinkEx x:Name="Link"></local:HyperlinkEx>
|
||||
<TextBlock
|
||||
x:Name="LinkTextBlock"
|
||||
Margin="2,0"
|
||||
>
|
||||
<local:HyperlinkEx
|
||||
x:Name="Link"
|
||||
Foreground="{Binding Theme.Heading}"
|
||||
/>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
@@ -109,7 +109,7 @@ public partial class InputWindow : Window
|
||||
else
|
||||
{
|
||||
newContent = InputHelp.ConvertToString(InputHelp.GetReducedBindings(Bindings));
|
||||
newContent = newContent.Replace("#menu: ", "# ");
|
||||
newContent = newContent.Replace(App.MenuSyntax + " ", "# ");
|
||||
File.WriteAllText(App.InputConf.Path, App.InputConf.Content = newContent);
|
||||
}
|
||||
|
||||
|
||||
@@ -122,39 +122,67 @@
|
||||
<Border x:Name="stackButtons" Grid.Row="3" Padding="10"
|
||||
Background="{Binding Path=ButtonBackground}" >
|
||||
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Center" >
|
||||
<Button x:Name="btnOK" Content=" OK " MinWidth="75" Margin="5,0,5,0"
|
||||
<Button x:Name="btnOK"
|
||||
Content=" OK "
|
||||
MinWidth="75"
|
||||
Margin="5,0,5,0"
|
||||
Width="{Binding Path=ButtonWidth}"
|
||||
Height="25"
|
||||
MinHeight="25"
|
||||
Visibility="{Binding Path=ShowOk}"
|
||||
IsDefault="{Binding Path=IsDefaultOK}"
|
||||
Click="BtnOK_Click" />
|
||||
<Button x:Name="btnYes" Content=" Yes " MinWidth="75" Margin="5,0,5,0"
|
||||
<Button x:Name="btnYes"
|
||||
Content=" Yes "
|
||||
Width="{Binding Path=ButtonWidth}"
|
||||
MinWidth="75"
|
||||
MinHeight="25"
|
||||
Margin="5,0,5,0"
|
||||
Visibility="{Binding Path=ShowYes}"
|
||||
IsDefault="{Binding Path=IsDefaultYes}"
|
||||
Click="BtnYes_Click"/>
|
||||
<Button x:Name="btnNo" Content=" No " MinWidth="75" Margin="5,0,5,0"
|
||||
<Button x:Name="btnNo"
|
||||
Content=" No "
|
||||
Width="{Binding Path=ButtonWidth}"
|
||||
MinWidth="75"
|
||||
MinHeight="25"
|
||||
Margin="5,0,5,0"
|
||||
Visibility="{Binding Path=ShowNo}"
|
||||
IsDefault="{Binding Path=IsDefaultNo}"
|
||||
Click="BtnNo_Click"/>
|
||||
<Button x:Name="btnAbort" Content=" Abort " MinWidth="75" Margin="5,0,5,0"
|
||||
<Button x:Name="btnAbort"
|
||||
Content=" Abort "
|
||||
Width="{Binding Path=ButtonWidth}"
|
||||
MinWidth="75"
|
||||
MinHeight="25"
|
||||
Margin="5,0,5,0"
|
||||
Visibility="{Binding Path=ShowAbort}"
|
||||
IsDefault="{Binding Path=IsDefaultAbort}"
|
||||
Click="BtnAbort_Click"/>
|
||||
<Button x:Name="btnRetry" Content=" Retry " MinWidth="75" Margin="5,0,5,0"
|
||||
<Button x:Name="btnRetry"
|
||||
Content=" Retry "
|
||||
Width="{Binding Path=ButtonWidth}"
|
||||
MinWidth="75"
|
||||
MinHeight="25"
|
||||
Margin="5,0,5,0"
|
||||
Visibility="{Binding Path=ShowRetry}"
|
||||
IsDefault="{Binding Path=IsDefaultRetry}"
|
||||
Click="BtnRetry_Click"/>
|
||||
<Button x:Name="btnIgnore" Content=" Ignore " MinWidth="75" Margin="5,0,5,0"
|
||||
<Button x:Name="btnIgnore"
|
||||
Content=" Ignore "
|
||||
Width="{Binding Path=ButtonWidth}"
|
||||
MinWidth="75"
|
||||
MinHeight="25"
|
||||
Margin="5,0,5,0"
|
||||
Visibility="{Binding Path=ShowIgnore}"
|
||||
IsDefault="{Binding Path=IsDefaultIgnore}"
|
||||
Click="BtnIgnore_Click"/>
|
||||
<Button x:Name="btnCancel" Content=" Cancel " MinWidth="75" Margin="5,0,5,0"
|
||||
<Button x:Name="btnCancel"
|
||||
Content=" Cancel "
|
||||
Width="{Binding Path=ButtonWidth}"
|
||||
MinWidth="75"
|
||||
MinHeight="25"
|
||||
Margin="5,0,5,0"
|
||||
Visibility="{Binding Path=ShowCancel}"
|
||||
IsDefault="{Binding Path=IsDefaultCancel}"
|
||||
Click="BtnCancel_Click"/>
|
||||
|
||||
@@ -96,13 +96,13 @@ public partial class MessageBoxEx : Window, INotifyPropertyChanged
|
||||
|
||||
public static void SetOwner(Window window)
|
||||
{
|
||||
IntPtr ownerHandle = GetOwnerHandle();
|
||||
IntPtr parentHandle = GetParentHandle();
|
||||
|
||||
if (ownerHandle != IntPtr.Zero)
|
||||
new WindowInteropHelper(window).Owner = ownerHandle;
|
||||
if (parentHandle != IntPtr.Zero)
|
||||
new WindowInteropHelper(window).Owner = parentHandle;
|
||||
}
|
||||
|
||||
public static IntPtr GetOwnerHandle()
|
||||
public static IntPtr GetParentHandle()
|
||||
{
|
||||
IntPtr foregroundWindow = GetForegroundWindow();
|
||||
GetWindowThreadProcessId(foregroundWindow, out var procID);
|
||||
|
||||
@@ -6,6 +6,183 @@
|
||||
xmlns:local="clr-namespace:MpvNet.Windows.WPF"
|
||||
>
|
||||
|
||||
<DataTemplate x:Key="ComboBoxCollapsedDataTemplate" >
|
||||
<TextBlock Text="{Binding Text}"/>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="ComboBoxExpandedDataTemplate" >
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Bottom">
|
||||
<Border>
|
||||
<TextBlock
|
||||
Text="{Binding Text}"
|
||||
Width="{Binding OptionWidth}"
|
||||
VerticalAlignment="Center"
|
||||
TextWrapping="Wrap"
|
||||
/>
|
||||
</Border>
|
||||
<Border>
|
||||
<TextBlock
|
||||
Text="{Binding Help}"
|
||||
MaxWidth="400"
|
||||
Padding="0,3"
|
||||
VerticalAlignment="Center"
|
||||
TextWrapping="Wrap"
|
||||
/>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
|
||||
<Style x:Key="ComboBoxToggleButton" TargetType="ToggleButton">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="ToggleButton">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="32" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Border
|
||||
x:Name="Border"
|
||||
Grid.ColumnSpan="2"
|
||||
CornerRadius="3"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="1"
|
||||
/>
|
||||
|
||||
<Path
|
||||
x:Name="Arrow"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Data="M 1,1.5 L 4.5,5 L 8,1.5"
|
||||
SnapsToDevicePixels="false"
|
||||
Stroke="{TemplateBinding Foreground}"
|
||||
StrokeThickness="1.5"
|
||||
/>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<ControlTemplate x:Key="ComboBoxTextBox" TargetType="TextBox">
|
||||
<Border x:Name="PART_ContentHost" Focusable="True" />
|
||||
</ControlTemplate>
|
||||
|
||||
<Style TargetType="{x:Type ComboBox}">
|
||||
<Setter Property="Foreground" Value="#333" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource PrimaryTextBrush}" />
|
||||
<Setter Property="SnapsToDevicePixels" Value="true"/>
|
||||
<Setter Property="OverridesDefaultStyle" Value="true"/>
|
||||
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
|
||||
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
|
||||
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
|
||||
<Setter Property="FontSize" Value="13" />
|
||||
<Setter Property="MinWidth" Value="150"/>
|
||||
<Setter Property="MinHeight" Value="25"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="ComboBox">
|
||||
<Grid>
|
||||
<ToggleButton
|
||||
Cursor="Hand"
|
||||
Name="ToggleButton"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
Background="{TemplateBinding Background}"
|
||||
Foreground="{TemplateBinding Foreground}"
|
||||
Style="{StaticResource ComboBoxToggleButton}"
|
||||
Grid.Column="2"
|
||||
Focusable="false"
|
||||
IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}"
|
||||
ClickMode="Press"
|
||||
/>
|
||||
|
||||
<ContentPresenter
|
||||
Name="ContentSite"
|
||||
IsHitTestVisible="False"
|
||||
Content="{TemplateBinding SelectionBoxItem}"
|
||||
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
|
||||
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
|
||||
Margin="10,3,30,3"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Left"
|
||||
/>
|
||||
|
||||
<TextBox
|
||||
x:Name="PART_EditableTextBox"
|
||||
Style="{x:Null}"
|
||||
Template="{StaticResource ComboBoxTextBox}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Margin="3,3,23,3"
|
||||
Focusable="True"
|
||||
Visibility="Hidden"
|
||||
IsReadOnly="{TemplateBinding IsReadOnly}"
|
||||
/>
|
||||
|
||||
<Popup
|
||||
Name="Popup"
|
||||
Placement="Bottom"
|
||||
IsOpen="{TemplateBinding IsDropDownOpen}"
|
||||
AllowsTransparency="True"
|
||||
Focusable="False"
|
||||
PopupAnimation="Slide"
|
||||
>
|
||||
|
||||
<Grid
|
||||
Name="DropDown"
|
||||
SnapsToDevicePixels="True"
|
||||
MinWidth="{TemplateBinding ActualWidth}"
|
||||
MaxHeight="{TemplateBinding MaxDropDownHeight}"
|
||||
>
|
||||
|
||||
<Border
|
||||
CornerRadius="3"
|
||||
x:Name="DropDownBorder"
|
||||
Background="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}, Path=Background}"
|
||||
BorderBrush="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}, Path=Foreground}"
|
||||
BorderThickness="1"
|
||||
/>
|
||||
|
||||
<ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True">
|
||||
<StackPanel
|
||||
IsItemsHost="True"
|
||||
KeyboardNavigation.DirectionalNavigation="Contained" />
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Popup>
|
||||
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="HasItems" Value="false">
|
||||
<Setter TargetName="DropDownBorder" Property="MinHeight" Value="95"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsGrouping" Value="true">
|
||||
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEditable" Value="true">
|
||||
<Setter Property="IsTabStop" Value="false"/>
|
||||
<Setter TargetName="PART_EditableTextBox" Property="Visibility" Value="Visible"/>
|
||||
<Setter TargetName="ContentSite" Property="Visibility" Value="Hidden"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsEnabled" Value="false">
|
||||
<Setter Property="Opacity" Value="0.56"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsMouseOver" Value="true">
|
||||
<Setter Property="BorderBrush" Value="#FF7EB4EA"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsFocused" Value="true">
|
||||
<Setter Property="BorderBrush" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.Theme.Heading}"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="local:HyperlinkEx">
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
@@ -53,17 +230,20 @@
|
||||
</Style>
|
||||
|
||||
<Style TargetType="TextBox">
|
||||
<Setter Property="MinHeight" Value="25" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type TextBox}">
|
||||
<Border x:Name="border"
|
||||
<Border
|
||||
x:Name="border"
|
||||
BorderBrush="{DynamicResource PrimaryTextBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
Background="{TemplateBinding Background}"
|
||||
CornerRadius="3"
|
||||
SnapsToDevicePixels="True">
|
||||
|
||||
<ScrollViewer x:Name="PART_ContentHost"
|
||||
<ScrollViewer
|
||||
x:Name="PART_ContentHost"
|
||||
Focusable="false"
|
||||
HorizontalScrollBarVisibility="Hidden"
|
||||
VerticalScrollBarVisibility="Hidden"/>
|
||||
|
||||
39
src/MpvNet.Windows/WinForms/MainForm.Designer.cs
generated
@@ -29,36 +29,35 @@ partial class MainForm
|
||||
/// </summary>
|
||||
void InitializeComponent()
|
||||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
components = new System.ComponentModel.Container();
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
|
||||
this.CursorTimer = new System.Windows.Forms.Timer(this.components);
|
||||
this.ProgressTimer = new System.Windows.Forms.Timer(this.components);
|
||||
this.SuspendLayout();
|
||||
CursorTimer = new System.Windows.Forms.Timer(components);
|
||||
ProgressTimer = new System.Windows.Forms.Timer(components);
|
||||
SuspendLayout();
|
||||
//
|
||||
// CursorTimer
|
||||
//
|
||||
this.CursorTimer.Enabled = true;
|
||||
this.CursorTimer.Interval = 1000;
|
||||
this.CursorTimer.Tick += new System.EventHandler(this.CursorTimer_Tick);
|
||||
CursorTimer.Enabled = true;
|
||||
CursorTimer.Interval = 1000;
|
||||
CursorTimer.Tick += CursorTimer_Tick;
|
||||
//
|
||||
// ProgressTimer
|
||||
//
|
||||
this.ProgressTimer.Tick += new System.EventHandler(this.ProgressTimer_Tick);
|
||||
ProgressTimer.Tick += ProgressTimer_Tick;
|
||||
//
|
||||
// MainForm
|
||||
//
|
||||
this.AllowDrop = true;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(288F, 288F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
this.BackColor = System.Drawing.Color.Black;
|
||||
this.ClientSize = new System.Drawing.Size(857, 444);
|
||||
this.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.Name = "MainForm";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.ResumeLayout(false);
|
||||
|
||||
AllowDrop = true;
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(288F, 288F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
BackColor = System.Drawing.Color.Black;
|
||||
ClientSize = new System.Drawing.Size(1243, 720);
|
||||
Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
Icon = (System.Drawing.Icon)resources.GetObject("$this.Icon");
|
||||
Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
Name = "MainForm";
|
||||
StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
ResumeLayout(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Threading;
|
||||
using System.Windows.Forms.Integration;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
using MpvNet.Windows.WPF;
|
||||
using MpvNet.Windows.UI;
|
||||
@@ -27,7 +28,6 @@ public partial class MainForm : Form
|
||||
public SnapManager SnapManager = new SnapManager();
|
||||
public IntPtr MpvWindowHandle { get; set; }
|
||||
public ElementHost? CommandPaletteHost { get; set; }
|
||||
public Dictionary<string, WpfControls.MenuItem> MenuItemDuplicate = new Dictionary<string, WpfControls.MenuItem>();
|
||||
public bool WasShown { get; set; }
|
||||
public static MainForm? Instance { get; set; }
|
||||
WpfControls.ContextMenu ContextMenu { get; } = new WpfControls.ContextMenu();
|
||||
@@ -68,7 +68,6 @@ public partial class MainForm : Form
|
||||
GuiCommand.Current.WindowScaleNet += GuiCommand_WindowScaleNet;
|
||||
GuiCommand.Current.ShowMenu += GuiCommand_ShowMenu;
|
||||
|
||||
if (Player.GPUAPI != "vulkan")
|
||||
Init();
|
||||
|
||||
_taskbarButtonCreatedMessage = RegisterWindowMessage("TaskbarButtonCreated");
|
||||
@@ -163,6 +162,7 @@ public partial class MainForm : Form
|
||||
|
||||
Player.ObservePropertyDouble("window-scale", PropChangeWindowScale);
|
||||
|
||||
Player.ProcessCommandLineArgsPost();
|
||||
Player.ProcessCommandLineFiles();
|
||||
}
|
||||
|
||||
@@ -211,7 +211,7 @@ public partial class MainForm : Form
|
||||
{
|
||||
BeginInvoke(() => {
|
||||
Screen screen = Screen.FromControl(this);
|
||||
Rectangle workingArea = GetWorkingArea(Handle, screen.WorkingArea);
|
||||
Rectangle workingArea = WinApiHelp.GetWorkingArea(Handle, screen.WorkingArea);
|
||||
|
||||
switch (direction)
|
||||
{
|
||||
@@ -286,7 +286,7 @@ public partial class MainForm : Form
|
||||
|
||||
lock (Player.MediaTracksLock)
|
||||
{
|
||||
var trackMenuItem = FindMenuItem(_("Track"));
|
||||
var trackMenuItem = FindMenuItem(_("Track"), "Track");
|
||||
|
||||
if (trackMenuItem != null)
|
||||
{
|
||||
@@ -348,7 +348,7 @@ public partial class MainForm : Form
|
||||
}
|
||||
}
|
||||
|
||||
var chaptersMenuItem = FindMenuItem(_("Chapter"));
|
||||
var chaptersMenuItem = FindMenuItem(_("Chapter"), "Chapters");
|
||||
|
||||
if (chaptersMenuItem != null)
|
||||
{
|
||||
@@ -369,7 +369,7 @@ public partial class MainForm : Form
|
||||
}
|
||||
}
|
||||
|
||||
var recentMenuItem = FindMenuItem(_("Recent Files"));
|
||||
var recentMenuItem = FindMenuItem(_("Recent Files"), "Recent");
|
||||
|
||||
if (recentMenuItem != null)
|
||||
{
|
||||
@@ -391,7 +391,7 @@ public partial class MainForm : Form
|
||||
recentMenuItem.Items.Add(clearMenuItem);
|
||||
}
|
||||
|
||||
var titlesMenuItem = FindMenuItem(_("Title"));
|
||||
var titlesMenuItem = FindMenuItem(_("Title"), "Titles");
|
||||
|
||||
if (titlesMenuItem != null)
|
||||
{
|
||||
@@ -424,7 +424,7 @@ public partial class MainForm : Form
|
||||
}
|
||||
}
|
||||
|
||||
var profilesMenuItem = FindMenuItem(_("Profile"));
|
||||
var profilesMenuItem = FindMenuItem(_("Profile"), "Profile");
|
||||
|
||||
if (profilesMenuItem != null && !profilesMenuItem.HasItems)
|
||||
{
|
||||
@@ -446,7 +446,7 @@ public partial class MainForm : Form
|
||||
}
|
||||
}
|
||||
|
||||
var customMenuItem = FindMenuItem(_("Custom"));
|
||||
var customMenuItem = FindMenuItem(_("Custom"), "Custom");
|
||||
|
||||
if (customMenuItem != null)
|
||||
{
|
||||
@@ -476,7 +476,14 @@ public partial class MainForm : Form
|
||||
}
|
||||
}
|
||||
|
||||
public WpfControls.MenuItem? FindMenuItem(string text) => FindMenuItem(text, ContextMenu.Items);
|
||||
public WpfControls.MenuItem? FindMenuItem(string text, string text2 = "") {
|
||||
var ret = FindMenuItem(text, ContextMenu.Items);
|
||||
|
||||
if (ret == null && text2 != "")
|
||||
return FindMenuItem(text2, ContextMenu.Items);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
WpfControls.MenuItem? FindMenuItem(string text, WpfControls.ItemCollection? items)
|
||||
{
|
||||
@@ -500,7 +507,7 @@ public partial class MainForm : Form
|
||||
return null;
|
||||
}
|
||||
|
||||
void SetFormPosAndSize(bool force = false, bool checkAutofit = true)
|
||||
void SetFormPosAndSize(bool force = false, bool checkAutofit = true, bool load = false)
|
||||
{
|
||||
if (!force)
|
||||
{
|
||||
@@ -515,7 +522,7 @@ public partial class MainForm : Form
|
||||
}
|
||||
|
||||
Screen screen = Screen.FromControl(this);
|
||||
Rectangle workingArea = GetWorkingArea(Handle, screen.WorkingArea);
|
||||
Rectangle workingArea = WinApiHelp.GetWorkingArea(Handle, screen.WorkingArea);
|
||||
int autoFitHeight = Convert.ToInt32(workingArea.Height * Player.Autofit);
|
||||
|
||||
if (App.AutofitAudio > 1)
|
||||
@@ -599,12 +606,12 @@ public partial class MainForm : Form
|
||||
Player.WasInitialSizeSet = true;
|
||||
}
|
||||
|
||||
SetSize(width, height, screen, checkAutofit);
|
||||
SetSize(width, height, screen, checkAutofit, load);
|
||||
}
|
||||
|
||||
void SetSize(int width, int height, Screen screen, bool checkAutofit = true)
|
||||
void SetSize(int width, int height, Screen screen, bool checkAutofit = true, bool load = false)
|
||||
{
|
||||
Rectangle workingArea = GetWorkingArea(Handle, screen.WorkingArea);
|
||||
Rectangle workingArea = WinApiHelp.GetWorkingArea(Handle, screen.WorkingArea);
|
||||
|
||||
int maxHeight = workingArea.Height - (Height - ClientSize.Height) - 2;
|
||||
int maxWidth = workingArea.Width - (Width - ClientSize.Width);
|
||||
@@ -647,40 +654,76 @@ public partial class MainForm : Form
|
||||
|
||||
Point middlePos = new Point(Left + Width / 2, Top + Height / 2);
|
||||
var rect = new Rect(new Rectangle(screen.Bounds.X, screen.Bounds.Y, width, height));
|
||||
AddWindowBorders(Handle, ref rect, GetDpi(Handle));
|
||||
WinApiHelp.AddWindowBorders(Handle, ref rect, GetDpi(Handle));
|
||||
|
||||
int left = middlePos.X - rect.Width / 2;
|
||||
int top = middlePos.Y - rect.Height / 2;
|
||||
width = rect.Width;
|
||||
height = rect.Height;
|
||||
|
||||
int left = middlePos.X - width / 2;
|
||||
int top = middlePos.Y - height / 2;
|
||||
|
||||
Rectangle currentRect = new Rectangle(Left, Top, Width, Height);
|
||||
|
||||
if (GetHorizontalLocation(screen) == -1) left = Left;
|
||||
if (GetHorizontalLocation(screen) == 1) left = currentRect.Right - rect.Width;
|
||||
if (GetHorizontalLocation(screen) == 1) left = currentRect.Right - width;
|
||||
|
||||
if (GetVerticalLocation(screen) == -1) top = Top;
|
||||
if (GetVerticalLocation(screen) == 1) top = currentRect.Bottom - rect.Height;
|
||||
if (GetVerticalLocation(screen) == 1) top = currentRect.Bottom - height;
|
||||
|
||||
Screen[] screens = Screen.AllScreens;
|
||||
|
||||
int minLeft = screens.Select(val => GetWorkingArea(Handle, val.WorkingArea).X).Min();
|
||||
int maxRight = screens.Select(val => GetWorkingArea(Handle, val.WorkingArea).Right).Max();
|
||||
int minTop = screens.Select(val => GetWorkingArea(Handle, val.WorkingArea).Y).Min();
|
||||
int maxBottom = screens.Select(val => GetWorkingArea(Handle, val.WorkingArea).Bottom).Max();
|
||||
int minLeft = screens.Select(val => WinApiHelp.GetWorkingArea(Handle, val.WorkingArea).X).Min();
|
||||
int maxRight = screens.Select(val => WinApiHelp.GetWorkingArea(Handle, val.WorkingArea).Right).Max();
|
||||
int minTop = screens.Select(val => WinApiHelp.GetWorkingArea(Handle, val.WorkingArea).Y).Min();
|
||||
int maxBottom = screens.Select(val => WinApiHelp.GetWorkingArea(Handle, val.WorkingArea).Bottom).Max();
|
||||
|
||||
if (load && CommandLine.Contains("geometry"))
|
||||
{
|
||||
string geometryString = CommandLine.GetValue("geometry");
|
||||
|
||||
var geometry = ParseGeometry(geometryString, WinApiHelp.GetWorkingArea(
|
||||
Handle, Screen.FromHandle(Handle).WorkingArea), width, height);
|
||||
|
||||
if (geometry.x != int.MaxValue)
|
||||
left = geometry.x;
|
||||
|
||||
if (geometry.y != int.MaxValue)
|
||||
top = geometry.y;
|
||||
}
|
||||
|
||||
if (left < minLeft)
|
||||
left = minLeft;
|
||||
|
||||
if (left + rect.Width > maxRight)
|
||||
left = maxRight - rect.Width;
|
||||
if (left + width > maxRight)
|
||||
left = maxRight - width;
|
||||
|
||||
if (top < minTop)
|
||||
top = minTop;
|
||||
|
||||
if (top + rect.Height > maxBottom)
|
||||
top = maxBottom - rect.Height;
|
||||
if (top + height > maxBottom)
|
||||
top = maxBottom - height;
|
||||
|
||||
uint SWP_NOACTIVATE = 0x0010;
|
||||
SetWindowPos(Handle, IntPtr.Zero, left, top, rect.Width, rect.Height, SWP_NOACTIVATE);
|
||||
SetWindowPos(Handle, IntPtr.Zero, left, top, width, height, SWP_NOACTIVATE);
|
||||
}
|
||||
|
||||
(int x, int y) ParseGeometry(string input, Rectangle workingArea, int width, int height)
|
||||
{
|
||||
int x = int.MaxValue;
|
||||
int y = int.MaxValue;
|
||||
|
||||
Match match = Regex.Match(input, @"^(\d+)%?:(\d+)%?$");
|
||||
|
||||
if (match.Success)
|
||||
{
|
||||
x = int.Parse(match.Groups[1].Value);
|
||||
y = int.Parse(match.Groups[2].Value);
|
||||
|
||||
x = workingArea.Left + Convert.ToInt32((workingArea.Width - width) / 100.0 * x);
|
||||
y = workingArea.Top + Convert.ToInt32((workingArea.Height - height) / 100.0 * y);
|
||||
}
|
||||
|
||||
return (x, y);
|
||||
}
|
||||
|
||||
public void CycleFullscreen(bool enabled)
|
||||
@@ -728,7 +771,7 @@ public partial class MainForm : Form
|
||||
|
||||
public int GetHorizontalLocation(Screen screen)
|
||||
{
|
||||
Rectangle workingArea = GetWorkingArea(Handle, screen.WorkingArea);
|
||||
Rectangle workingArea = WinApiHelp.GetWorkingArea(Handle, screen.WorkingArea);
|
||||
Rectangle rect = new Rectangle(Left - workingArea.X, Top - workingArea.Y, Width, Height);
|
||||
|
||||
if (workingArea.Width / (float)Width < 1.1)
|
||||
@@ -745,7 +788,7 @@ public partial class MainForm : Form
|
||||
|
||||
public int GetVerticalLocation(Screen screen)
|
||||
{
|
||||
Rectangle workingArea = GetWorkingArea(Handle, screen.WorkingArea);
|
||||
Rectangle workingArea = WinApiHelp.GetWorkingArea(Handle, screen.WorkingArea);
|
||||
Rectangle rect = new Rectangle(Left - workingArea.X, Top - workingArea.Y, Width, Height);
|
||||
|
||||
if (workingArea.Height / (float)Height < 1.1)
|
||||
@@ -767,17 +810,12 @@ public partial class MainForm : Form
|
||||
|
||||
var (menuBindings, confBindings) = App.InputConf.GetBindings();
|
||||
_confBindings = confBindings;
|
||||
var activeBindings = InputHelp.GetActiveBindings(menuBindings);
|
||||
|
||||
foreach (Binding binding in menuBindings)
|
||||
{
|
||||
Binding tempBinding = binding;
|
||||
|
||||
if (MenuItemDuplicate.ContainsKey(tempBinding.Command) && tempBinding.Input != "")
|
||||
{
|
||||
var mi = MenuItemDuplicate[tempBinding.Command];
|
||||
mi.InputGestureText = mi.InputGestureText + ", " + tempBinding.Input;
|
||||
}
|
||||
|
||||
if (!binding.IsMenu)
|
||||
continue;
|
||||
|
||||
@@ -785,9 +823,6 @@ public partial class MainForm : Form
|
||||
|
||||
if (menuItem != null)
|
||||
{
|
||||
if (tempBinding.Input != "")
|
||||
MenuItemDuplicate[tempBinding.Command] = menuItem;
|
||||
|
||||
menuItem.Click += (sender, args) => {
|
||||
try {
|
||||
TaskHelp.Run(() => {
|
||||
@@ -803,7 +838,7 @@ public partial class MainForm : Form
|
||||
}
|
||||
};
|
||||
|
||||
menuItem.InputGestureText = tempBinding.Input;
|
||||
menuItem.InputGestureText = InputHelp.GetBindingsForCommand(activeBindings, tempBinding.Command);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1020,7 +1055,7 @@ public partial class MainForm : Form
|
||||
{
|
||||
Rect rc = Marshal.PtrToStructure<Rect>(m.LParam);
|
||||
Rect r = rc;
|
||||
SubtractWindowBorders(Handle, ref r, GetDpi(Handle));
|
||||
WinApiHelp.SubtractWindowBorders(Handle, ref r, GetDpi(Handle));
|
||||
|
||||
int c_w = r.Right - r.Left, c_h = r.Bottom - r.Top;
|
||||
Size videoSize = Player.VideoSize;
|
||||
@@ -1034,7 +1069,7 @@ public partial class MainForm : Form
|
||||
|
||||
int[] d_corners = { d_w, d_h, -d_w, -d_h };
|
||||
int[] corners = { rc.Left, rc.Top, rc.Right, rc.Bottom };
|
||||
int corner = GetResizeBorder(m.WParam.ToInt32());
|
||||
int corner = WinApiHelp.GetResizeBorder(m.WParam.ToInt32());
|
||||
|
||||
if (corner >= 0)
|
||||
corners[corner] -= d_corners[corner];
|
||||
@@ -1222,10 +1257,8 @@ public partial class MainForm : Form
|
||||
protected override void OnLoad(EventArgs e)
|
||||
{
|
||||
base.OnLoad(e);
|
||||
if (Player.GPUAPI != "vulkan")
|
||||
Player.VideoSizeAutoResetEvent.WaitOne(App.StartThreshold);
|
||||
_lastCycleFullscreen = Environment.TickCount;
|
||||
SetFormPosAndSize();
|
||||
SetFormPosAndSize(false, true, true);
|
||||
}
|
||||
|
||||
protected override void OnLostFocus(EventArgs e)
|
||||
@@ -1238,9 +1271,6 @@ public partial class MainForm : Form
|
||||
{
|
||||
base.OnShown(e);
|
||||
|
||||
if (Player.GPUAPI == "vulkan")
|
||||
Init();
|
||||
|
||||
if (WindowState == FormWindowState.Maximized)
|
||||
Player.SetPropertyBool("window-maximized", true);
|
||||
|
||||
@@ -1252,9 +1282,14 @@ public partial class MainForm : Form
|
||||
InitAndBuildContextMenu();
|
||||
Cursor.Position = new Point(Cursor.Position.X + 1, Cursor.Position.Y);
|
||||
GlobalHotkey.RegisterGlobalHotkeys(Handle);
|
||||
TaskHelp.Run(WinMpvHelp.CopyMpvNetCom);
|
||||
WasShown = true;
|
||||
StrongReferenceMessenger.Default.Send(new MainWindowIsLoadedMessage());
|
||||
|
||||
TaskHelp.Run(() => {
|
||||
System.Windows.Application.Current.Dispatcher.BeginInvoke(() => {
|
||||
WinMpvHelp.Setup();
|
||||
}, DispatcherPriority.Background);
|
||||
});
|
||||
}
|
||||
|
||||
void ContextMenu_Closed(object sender, System.Windows.RoutedEventArgs e) => MenuAutoResetEvent.Set();
|
||||
@@ -1386,7 +1421,7 @@ public partial class MainForm : Form
|
||||
|
||||
public static int GetDpi(IntPtr hwnd)
|
||||
{
|
||||
if (Environment.OSVersion.Version >= WindowsTen1607 && hwnd != IntPtr.Zero)
|
||||
if (Environment.OSVersion.Version >= WinApiHelp.WindowsTen1607 && hwnd != IntPtr.Zero)
|
||||
return GetDpiForWindow(hwnd);
|
||||
else
|
||||
using (Graphics gx = Graphics.FromHwnd(hwnd))
|
||||
|
||||
@@ -1,4 +1,64 @@
|
||||
<root>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
using MpvNet.Windows.Help;
|
||||
using MpvNet.Windows.Native;
|
||||
|
||||
using static MpvNet.Windows.Native.WinApi;
|
||||
|
||||
namespace MpvNet.Windows.WinForms;
|
||||
|
||||
public class SnapManager
|
||||
@@ -35,7 +34,7 @@ public class SnapManager
|
||||
void FindSnap(ref Rectangle effectiveBounds)
|
||||
{
|
||||
Screen currentScreen = Screen.FromPoint(effectiveBounds.Location);
|
||||
Rectangle workingArea = GetWorkingArea(Handle, currentScreen.WorkingArea);
|
||||
Rectangle workingArea = WinApiHelp.GetWorkingArea(Handle, currentScreen.WorkingArea);
|
||||
|
||||
if (InSnapRange(effectiveBounds.Left, workingArea.Left + AnchorDistance))
|
||||
effectiveBounds.X = workingArea.Left + AnchorDistance;
|
||||
|
||||
@@ -20,21 +20,77 @@ EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|ARM = Debug|ARM
|
||||
Debug|ARM64 = Debug|ARM64
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|ARM = Release|ARM
|
||||
Release|ARM64 = Release|ARM64
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Release|ARM64.Build.0 = Release|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Release|x64.Build.0 = Release|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Release|x86.Build.0 = Release|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Release|ARM64.Build.0 = Release|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Release|x64.Build.0 = Release|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Release|x86.Build.0 = Release|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|ARM64.Build.0 = Release|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|x64.Build.0 = Release|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -10,7 +10,6 @@ namespace MpvNet;
|
||||
public class AppClass
|
||||
{
|
||||
public List<string> TempFiles { get; } = new ();
|
||||
public Dictionary<string, string> CommandLineArguments { get; } = new ();
|
||||
|
||||
public string ConfPath { get => Player.ConfigFolder + "mpvnet.conf"; }
|
||||
public string ProcessInstance { get; set; } = "single";
|
||||
@@ -20,6 +19,7 @@ public class AppClass
|
||||
public string StartSize { get; set; } = "height-session";
|
||||
public string Language { get; set; } = "system";
|
||||
public string CommandLine { get; set; } = Environment.CommandLine;
|
||||
public string MenuSyntax { get; set; } = "#menu:";
|
||||
|
||||
public bool AutoLoadFolder { get; set; } = true;
|
||||
public bool DebugMode { get; set; }
|
||||
@@ -30,7 +30,6 @@ public class AppClass
|
||||
public bool RememberVolume { get; set; } = true;
|
||||
public bool RememberWindowPosition { get; set; }
|
||||
|
||||
public int StartThreshold { get; set; } = 1500;
|
||||
public int RecentCount { get; set; } = 15;
|
||||
|
||||
public float AutofitAudio { get; set; } = 0.7f;
|
||||
@@ -145,6 +144,7 @@ public class AppClass
|
||||
case "language": Language = value; return true;
|
||||
case "light-theme": LightTheme = value.Trim('\'', '"'); return true;
|
||||
case "media-info": MediaInfo = value == "yes"; return true;
|
||||
case "menu-syntax": MenuSyntax = value; return true;
|
||||
case "minimum-aspect-ratio-audio": MinimumAspectRatioAudio = value.ToFloat(); return true;
|
||||
case "minimum-aspect-ratio": MinimumAspectRatio = value.ToFloat(); return true;
|
||||
case "process-instance": ProcessInstance = value; return true;
|
||||
@@ -153,7 +153,6 @@ public class AppClass
|
||||
case "remember-volume": RememberVolume = value == "yes"; return true;
|
||||
case "remember-window-position": RememberWindowPosition = value == "yes"; return true;
|
||||
case "start-size": StartSize = value; return true;
|
||||
case "start-threshold": StartThreshold = value.ToInt(1500); return true;
|
||||
case "video-file-extensions": FileTypes.Video = value.Split(" ,;".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); return true;
|
||||
|
||||
default:
|
||||
|
||||
@@ -18,7 +18,6 @@ public class Command
|
||||
["play-pause"] = PlayPause,
|
||||
["shell-execute"] = args => ProcessHelp.ShellExecute(args[0]),
|
||||
["show-text"] = args => ShowText(args[0], Convert.ToInt32(args[1]), Convert.ToInt32(args[2])),
|
||||
["show-commands"] = args => ShowCommands(),
|
||||
["cycle-audio"] = args => CycleAudio(),
|
||||
["cycle-subtitles"] = args => CycleSubtitles(),
|
||||
["playlist-first"] = args => PlaylistFirst(),
|
||||
@@ -52,37 +51,6 @@ public class Command
|
||||
}
|
||||
}
|
||||
|
||||
public static void ShowCommands()
|
||||
{
|
||||
string json = Core.GetPropertyString("command-list");
|
||||
var enumerator = JsonDocument.Parse(json).RootElement.EnumerateArray();
|
||||
var commands = enumerator.OrderBy(it => it.GetProperty("name").GetString());
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
foreach (var cmd in commands)
|
||||
{
|
||||
sb.AppendLine();
|
||||
sb.AppendLine(cmd.GetProperty("name").GetString());
|
||||
|
||||
foreach (var args in cmd.GetProperty("args").EnumerateArray())
|
||||
{
|
||||
string value = args.GetProperty("name").GetString() + " <" +
|
||||
args.GetProperty("type").GetString()!.ToLower() + ">";
|
||||
|
||||
if (args.GetProperty("optional").GetBoolean())
|
||||
value = "[" + value + "]";
|
||||
|
||||
sb.AppendLine(" " + value);
|
||||
}
|
||||
}
|
||||
|
||||
string header = BR +
|
||||
"https://mpv.io/manual/master/#list-of-input-commands" + BR2 +
|
||||
"https://github.com/stax76/mpv-scripts#command_palette" + BR;
|
||||
|
||||
ShowTextWithEditor("Input Commands", header + sb.ToString());
|
||||
}
|
||||
|
||||
public static void ShowText(string text, int duration = 0, int fontSize = 0)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text))
|
||||
@@ -98,14 +66,6 @@ public class Command
|
||||
"}${osd-ass-cc/1}" + text + "\" " + duration);
|
||||
}
|
||||
|
||||
public static void ShowTextWithEditor(string name, string text)
|
||||
{
|
||||
string file = Path.Combine(Path.GetTempPath(), name + ".txt");
|
||||
App.TempFiles.Add(file);
|
||||
File.WriteAllText(file, BR + text.Trim() + BR);
|
||||
ProcessHelp.ShellExecute(file);
|
||||
}
|
||||
|
||||
public static void CycleAudio()
|
||||
{
|
||||
Player.UpdateExternalTracks();
|
||||
|
||||
73
src/MpvNet/CommandLine.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
|
||||
namespace MpvNet;
|
||||
|
||||
public class CommandLine
|
||||
{
|
||||
static List<StringPair>? _arguments;
|
||||
|
||||
public static List<StringPair> Arguments
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_arguments != null)
|
||||
return _arguments;
|
||||
|
||||
_arguments = new();
|
||||
|
||||
foreach (string i in Environment.GetCommandLineArgs().Skip(1))
|
||||
{
|
||||
string arg = i;
|
||||
|
||||
if (!arg.StartsWith("--"))
|
||||
continue;
|
||||
|
||||
if (!arg.Contains('='))
|
||||
{
|
||||
if (arg.Contains("--no-"))
|
||||
{
|
||||
arg = arg.Replace("--no-", "--");
|
||||
arg += "=no";
|
||||
}
|
||||
else
|
||||
arg += "=yes";
|
||||
}
|
||||
|
||||
string left = arg[2..arg.IndexOf("=")];
|
||||
string right = arg[(left.Length + 3)..];
|
||||
|
||||
if (string.IsNullOrEmpty(left))
|
||||
continue;
|
||||
|
||||
switch (left)
|
||||
{
|
||||
case "script": left = "scripts"; break;
|
||||
case "audio-file": left = "audio-files"; break;
|
||||
case "sub-file": left = "sub-files"; break;
|
||||
case "external-file": left = "external-files"; break;
|
||||
}
|
||||
|
||||
_arguments.Add(new StringPair(left, right));
|
||||
}
|
||||
|
||||
return _arguments;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool Contains(string name)
|
||||
{
|
||||
foreach (StringPair pair in Arguments)
|
||||
if (pair.Name == name)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static string GetValue(string name)
|
||||
{
|
||||
foreach (StringPair pair in Arguments)
|
||||
if (pair.Name == name)
|
||||
return pair.Value;
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
namespace MpvNet.Help;
|
||||
|
||||
namespace MpvNet.Help;
|
||||
|
||||
public static class ProcessHelp
|
||||
{
|
||||
public static void Execute(string file, string arguments = "", bool shellExecute = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
using Process proc = new Process();
|
||||
proc.StartInfo.FileName = file;
|
||||
@@ -10,6 +13,11 @@ public static class ProcessHelp
|
||||
proc.StartInfo.UseShellExecute = shellExecute;
|
||||
proc.Start();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Terminal.WriteError(ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public static void ShellExecute(string file, string arguments = "") => Execute(file, arguments, true);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ public class InputConf
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasMenu => Content.Contains("#menu:") || Content.Contains("#! ");
|
||||
public bool HasMenu => Content.Contains(App.MenuSyntax + " ");
|
||||
|
||||
public (List<Binding> menuBindings, List<Binding>? confBindings) GetBindings()
|
||||
{
|
||||
|
||||
@@ -125,8 +125,6 @@ public static class InputHelp
|
||||
new (_("View") + " > " + _("More"), _("Show Console"), "script-binding console/enable", "`"),
|
||||
new (_("View") + " > " + _("More"), _("Show Audio Devices"), "script-message-to mpvnet show-audio-devices"),
|
||||
new (_("View") + " > " + _("More"), _("Show Commands"), "script-message-to mpvnet show-commands", "F2"),
|
||||
new (_("View") + " > " + _("More"), _("Show Demuxers"), "script-message-to mpvnet show-demuxers"),
|
||||
new (_("View") + " > " + _("More"), _("Show Decoders"), "script-message-to mpvnet show-decoders"),
|
||||
new (_("View") + " > " + _("More"), _("Show Bindings"), "script-message-to mpvnet show-bindings"),
|
||||
|
||||
new (_("Window"), _("Fullscreen"), "cycle fullscreen", "Enter"),
|
||||
@@ -149,11 +147,16 @@ public static class InputHelp
|
||||
|
||||
new (_("Settings"), _("Show Config Editor"), "script-message-to mpvnet show-conf-editor", "Ctrl+,"),
|
||||
new (_("Settings"), _("Show Input Editor"), "script-message-to mpvnet show-input-editor", "Ctrl+i"),
|
||||
new (_("Settings"), "-"),
|
||||
new (_("Settings"), _("Edit mpv.conf"), "script-message-to mpvnet edit-conf-file mpv.conf", "c"),
|
||||
new (_("Settings"), _("Edit input.conf"), "script-message-to mpvnet edit-conf-file input.conf", "k"),
|
||||
new (_("Settings"), "-"),
|
||||
new (_("Settings"), _("Open Config Folder"), "script-message-to mpvnet open-conf-folder", "Ctrl+f"),
|
||||
new (_("Settings") + " > " + _("Setup"), _("Register video file associations"), "script-message-to mpvnet reg-file-assoc video"),
|
||||
new (_("Settings") + " > " + _("Setup"), _("Register audio file associations"), "script-message-to mpvnet reg-file-assoc audio"),
|
||||
new (_("Settings") + " > " + _("Setup"), _("Register image file associations"), "script-message-to mpvnet reg-file-assoc image"),
|
||||
new (_("Settings") + " > " + _("Setup"), _("Unregister file associations"), "script-message-to mpvnet reg-file-assoc unreg"),
|
||||
new (_("Settings") + " > " + _("Setup"), _("Add mpv.net to Path environment variable"), "script-message-to mpvnet add-to-path"),
|
||||
|
||||
new (_("Tools"), _("Set/clear A-B loop points"), "ab-loop", "l"),
|
||||
new (_("Tools"), _("Toggle infinite file looping"), "cycle-values loop-file inf no", "L"),
|
||||
@@ -174,11 +177,10 @@ public static class InputHelp
|
||||
|
||||
new ("", "", "quit", "q", _("Exit")),
|
||||
new ("", "", "script-message-to mpvnet show-menu", "MBTN_Right", _("Show Menu")),
|
||||
new ("", "", "quit", "Power", _("Exit")),
|
||||
new ("", "", "cycle pause", "Play", _("Play/Pause")),
|
||||
new ("", "", "cycle pause", "Pause", _("Play/Pause")),
|
||||
new ("", "", "cycle pause", "PlayPause", _("Play/Pause")),
|
||||
new ("", "", "cycle pause", "MBTN_Mid", _("Play/Pause")),
|
||||
new ("", "", "script-message-to mpvnet play-pause", "Play", _("Play/Pause")),
|
||||
new ("", "", "script-message-to mpvnet play-pause", "Pause", _("Play/Pause")),
|
||||
new ("", "", "script-message-to mpvnet play-pause", "PlayPause", _("Play/Pause")),
|
||||
new ("", "", "script-message-to mpvnet play-pause", "MBTN_Mid", _("Play/Pause")),
|
||||
new ("", "", "stop", "Stop", _("Stop")),
|
||||
new ("", "", "seek 60", "Forward", _("Forward")),
|
||||
new ("", "", "seek -60", "Rewind", _("Backward")),
|
||||
@@ -207,6 +209,8 @@ public static class InputHelp
|
||||
new ("", "", "no-osd seek -5", "Ctrl+Wheel_Down", _("Seek Backward")),
|
||||
new ("", "", "quit 4", "Esc", _("Quit encoding")),
|
||||
new ("", "", "quit 4", "q", _("Quit encoding")),
|
||||
new ("", "", "quit", "Power", _("Exit")),
|
||||
|
||||
//new (_("Command Palette"), _("Commands"), "script-message-to mpvnet show-command-palette", "F1"),
|
||||
};
|
||||
|
||||
@@ -321,18 +325,11 @@ public static class InputHelp
|
||||
|
||||
line = line[(line.IndexOf(" ") + 1)..];
|
||||
|
||||
if (line.Contains("#menu:"))
|
||||
if (line.Contains(App.MenuSyntax))
|
||||
{
|
||||
binding.Comment = line[(line.IndexOf("#menu:") + 6)..].Trim();
|
||||
binding.Comment = line[(line.IndexOf(App.MenuSyntax) + App.MenuSyntax.Length)..].Trim();
|
||||
binding.IsMenu = true;
|
||||
line = line[..line.IndexOf("#menu:")];
|
||||
}
|
||||
else if (line.Contains("#!"))
|
||||
{
|
||||
binding.Comment = line[(line.IndexOf("#!") + 2)..].Trim();
|
||||
binding.IsMenu = true;
|
||||
binding.IsShortMenuSyntax = true;
|
||||
line = line[..line.IndexOf("#!")];
|
||||
line = line[..line.IndexOf(App.MenuSyntax)];
|
||||
}
|
||||
else if (line.Contains("#custom-menu:"))
|
||||
{
|
||||
@@ -432,10 +429,10 @@ public static class InputHelp
|
||||
|
||||
value = value[(value.IndexOf(" ") + 1)..];
|
||||
|
||||
if (value.Contains("#menu:"))
|
||||
if (value.Contains(App.MenuSyntax))
|
||||
{
|
||||
binding.Comment = value[(value.IndexOf("#menu:") + 6)..].Trim();
|
||||
value = value[..value.IndexOf("#menu:")];
|
||||
binding.Comment = value[(value.IndexOf(App.MenuSyntax) + App.MenuSyntax.Length)..].Trim();
|
||||
value = value[..value.IndexOf(App.MenuSyntax)];
|
||||
|
||||
if (binding.Comment.Contains(';'))
|
||||
binding.Comment = binding.Comment[(binding.Comment.IndexOf(";") + 1)..].Trim();
|
||||
@@ -454,4 +451,41 @@ public static class InputHelp
|
||||
}
|
||||
return bindings;
|
||||
}
|
||||
|
||||
public static Dictionary<string, Binding> GetActiveBindings(List<Binding> bindings)
|
||||
{
|
||||
Dictionary<string, Binding> ret = new();
|
||||
|
||||
foreach (Binding binding in bindings)
|
||||
{
|
||||
if (binding.Input == "" || binding.Command == "")
|
||||
continue;
|
||||
|
||||
ret[binding.Input] = binding;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static string GetBindingsForCommand(Dictionary<string, Binding> activeBindings, string command)
|
||||
{
|
||||
List<string> keys = new();
|
||||
int charCount = 0;
|
||||
|
||||
foreach (var it in activeBindings)
|
||||
{
|
||||
if (it.Value.Command != command)
|
||||
continue;
|
||||
|
||||
Binding binding = it.Value;
|
||||
|
||||
if (!keys.Contains(binding.Input) && (charCount + binding.Input.Length) < 20 && keys.Count < 2)
|
||||
{
|
||||
keys.Add(binding.Input);
|
||||
charCount += binding.Input.Length;
|
||||
}
|
||||
}
|
||||
|
||||
return string.Join(", ", keys);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ public class MpvClient
|
||||
OnEndFile(data);
|
||||
}
|
||||
break;
|
||||
case mpv_event_id.MPV_EVENT_FILE_LOADED:
|
||||
case mpv_event_id.MPV_EVENT_FILE_LOADED: // triggered after MPV_EVENT_START_FILE
|
||||
OnFileLoaded();
|
||||
break;
|
||||
case mpv_event_id.MPV_EVENT_PROPERTY_CHANGE:
|
||||
@@ -82,7 +82,7 @@ public class MpvClient
|
||||
case mpv_event_id.MPV_EVENT_COMMAND_REPLY:
|
||||
OnCommandReply();
|
||||
break;
|
||||
case mpv_event_id.MPV_EVENT_START_FILE:
|
||||
case mpv_event_id.MPV_EVENT_START_FILE: // triggered before MPV_EVENT_FILE_LOADED
|
||||
OnStartFile();
|
||||
break;
|
||||
case mpv_event_id.MPV_EVENT_AUDIO_RECONFIG:
|
||||
|
||||
@@ -50,7 +50,6 @@ public class MainPlayer : MpvClient
|
||||
public float AutofitLarger { get; set; } = 0.8f;
|
||||
|
||||
public AutoResetEvent ShutdownAutoResetEvent { get; } = new AutoResetEvent(false);
|
||||
public AutoResetEvent VideoSizeAutoResetEvent { get; } = new AutoResetEvent(false);
|
||||
public nint MainHandle { get; set; }
|
||||
public List<MediaTrack> MediaTracks { get; set; } = new List<MediaTrack>();
|
||||
public List<TimeSpan> BluRayTitles { get; } = new List<TimeSpan>();
|
||||
@@ -64,7 +63,7 @@ public class MainPlayer : MpvClient
|
||||
public event Action<int>? PlaylistPosChanged;
|
||||
public event Action<Size>? VideoSizeChanged;
|
||||
|
||||
public void Init(IntPtr formHandle)
|
||||
public void Init(IntPtr formHandle, bool processCommandLineArguments = true)
|
||||
{
|
||||
App.ApplyShowMenuFix();
|
||||
|
||||
@@ -98,7 +97,6 @@ public class MainPlayer : MpvClient
|
||||
SetPropertyBool("input-default-bindings", true);
|
||||
SetPropertyBool("input-builtin-bindings", false);
|
||||
|
||||
SetPropertyString("watch-later-options", "mute");
|
||||
SetPropertyString("screenshot-directory", "~~desktop/");
|
||||
SetPropertyString("osd-playing-msg", "${media-title}");
|
||||
SetPropertyString("osc", "yes");
|
||||
@@ -111,11 +109,12 @@ public class MainPlayer : MpvClient
|
||||
if (!string.IsNullOrEmpty(UsedInputConfContent))
|
||||
SetPropertyString("input-conf", @"memory://" + UsedInputConfContent);
|
||||
|
||||
if (processCommandLineArguments)
|
||||
ProcessCommandLineArgs();
|
||||
|
||||
if (App.CommandLineArguments.ContainsKey("config-dir"))
|
||||
if (CommandLine.Contains("config-dir"))
|
||||
{
|
||||
string configDir = App.CommandLineArguments["config-dir"];
|
||||
string configDir = CommandLine.GetValue("config-dir");
|
||||
string fullPath = System.IO.Path.GetFullPath(configDir);
|
||||
App.InputConf.Path = fullPath.AddSep() + "input.conf";
|
||||
string content = App.InputConf.GetContent();
|
||||
@@ -152,16 +151,20 @@ public class MainPlayer : MpvClient
|
||||
// this means Lua scripts that use idle might not work correctly
|
||||
SetPropertyString("idle", "yes");
|
||||
|
||||
ObservePropertyString("path", value => Path = value);
|
||||
|
||||
ObservePropertyBool("pause", value => {
|
||||
Paused = value;
|
||||
Pause?.Invoke();
|
||||
});
|
||||
|
||||
ObservePropertyInt("video-rotate", value => {
|
||||
VideoRotate = GetPropertyInt("video-rotate");
|
||||
|
||||
ObservePropertyInt("video-rotate", value =>
|
||||
{
|
||||
if (VideoRotate != value)
|
||||
{
|
||||
VideoRotate = value;
|
||||
UpdateVideoSize("dwidth", "dheight");
|
||||
}
|
||||
});
|
||||
|
||||
ObservePropertyInt("playlist-pos", value => {
|
||||
@@ -173,9 +176,6 @@ public class MainPlayer : MpvClient
|
||||
CommandV("quit");
|
||||
});
|
||||
|
||||
if (!GetPropertyBool("osd-scale-by-window"))
|
||||
App.StartThreshold = 0;
|
||||
|
||||
Initialized?.Invoke();
|
||||
}
|
||||
|
||||
@@ -269,9 +269,11 @@ public class MainPlayer : MpvClient
|
||||
Dictionary<string, string>? _Conf;
|
||||
|
||||
public Dictionary<string, string> Conf {
|
||||
get {
|
||||
if (_Conf == null)
|
||||
get
|
||||
{
|
||||
if (_Conf != null)
|
||||
return _Conf;
|
||||
|
||||
App.ApplyInputDefaultBindingsFix();
|
||||
|
||||
_Conf = new Dictionary<string, string>();
|
||||
@@ -282,9 +284,17 @@ public class MainPlayer : MpvClient
|
||||
{
|
||||
string line = it.TrimStart(' ', '-').TrimEnd();
|
||||
|
||||
if (!line.Contains('=') || line.StartsWith("#"))
|
||||
if (line.StartsWith("#"))
|
||||
continue;
|
||||
|
||||
if (!line.Contains('='))
|
||||
{
|
||||
if (Regex.Match(line, "^[\\w-]+$").Success)
|
||||
line += "=yes";
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
string key = line[..line.IndexOf("=")].Trim();
|
||||
string value = line[(line.IndexOf("=") + 1)..].Trim();
|
||||
|
||||
@@ -299,7 +309,6 @@ public class MainPlayer : MpvClient
|
||||
|
||||
foreach (var i in _Conf)
|
||||
ProcessProperty(i.Key, i.Value);
|
||||
}
|
||||
|
||||
return _Conf;
|
||||
}
|
||||
@@ -307,19 +316,18 @@ public class MainPlayer : MpvClient
|
||||
|
||||
void UpdateVideoSize(string w, string h)
|
||||
{
|
||||
Size size = new Size(GetPropertyInt(w), GetPropertyInt(h));
|
||||
|
||||
if (size.Width == 0 || size.Height == 0)
|
||||
if (string.IsNullOrEmpty(Path))
|
||||
return;
|
||||
|
||||
Size size = new Size(GetPropertyInt(w), GetPropertyInt(h));
|
||||
|
||||
if (VideoRotate == 90 || VideoRotate == 270)
|
||||
size = new Size(size.Height, size.Width);
|
||||
|
||||
if (VideoSize != size)
|
||||
if (size != VideoSize && size != Size.Empty)
|
||||
{
|
||||
VideoSize = size;
|
||||
VideoSizeChanged?.Invoke(size);
|
||||
VideoSizeAutoResetEvent.Set();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,24 +357,27 @@ public class MainPlayer : MpvClient
|
||||
base.OnLogMessage(data);
|
||||
}
|
||||
|
||||
protected override void OnVideoReconfig()
|
||||
{
|
||||
UpdateVideoSize("dwidth", "dheight");
|
||||
base.OnVideoReconfig();
|
||||
}
|
||||
|
||||
protected override void OnEndFile(mpv_event_end_file data)
|
||||
{
|
||||
base.OnEndFile(data);
|
||||
FileEnded = true;
|
||||
}
|
||||
|
||||
protected override void OnVideoReconfig()
|
||||
{
|
||||
UpdateVideoSize("dwidth", "dheight");
|
||||
base.OnVideoReconfig();
|
||||
}
|
||||
|
||||
// executed before OnFileLoaded
|
||||
protected override void OnStartFile()
|
||||
{
|
||||
Path = GetPropertyString("path");
|
||||
base.OnStartFile();
|
||||
TaskHelp.Run(LoadFolder);
|
||||
}
|
||||
|
||||
// executed after OnStartFile
|
||||
protected override void OnFileLoaded()
|
||||
{
|
||||
Duration = TimeSpan.FromSeconds(GetPropertyDouble("duration"));
|
||||
@@ -374,13 +385,8 @@ public class MainPlayer : MpvClient
|
||||
if (App.StartSize == "video")
|
||||
WasInitialSizeSet = false;
|
||||
|
||||
string path = GetPropertyString("path");
|
||||
|
||||
if (!FileTypes.Video.Contains(path.Ext()) || FileTypes.Audio.Contains(path.Ext()))
|
||||
{
|
||||
if (!FileTypes.Video.Contains(Path.Ext()) || FileTypes.Audio.Contains(Path.Ext()))
|
||||
UpdateVideoSize("width", "height");
|
||||
VideoSizeAutoResetEvent.Set();
|
||||
}
|
||||
|
||||
TaskHelp.Run(UpdateTracks);
|
||||
|
||||
@@ -409,75 +415,28 @@ public class MainPlayer : MpvClient
|
||||
|
||||
public void ProcessCommandLineArgs()
|
||||
{
|
||||
foreach (string i in Environment.GetCommandLineArgs().Skip(1))
|
||||
foreach (var pair in CommandLine.Arguments)
|
||||
{
|
||||
string arg = i;
|
||||
|
||||
if (!arg.StartsWith("--"))
|
||||
if (pair.Name.EndsWith("-add"))
|
||||
continue;
|
||||
|
||||
if (arg == "--profile=help")
|
||||
{
|
||||
Console.WriteLine(GetProfiles());
|
||||
continue;
|
||||
ProcessProperty(pair.Name, pair.Value);
|
||||
|
||||
if (!App.ProcessProperty(pair.Name, pair.Value))
|
||||
SetPropertyString(pair.Name, pair.Value);
|
||||
}
|
||||
else if (arg == "--vd=help" || arg == "--ad=help")
|
||||
{
|
||||
Console.WriteLine(GetDecoders());
|
||||
continue;
|
||||
}
|
||||
else if (arg == "--audio-device=help")
|
||||
{
|
||||
Console.WriteLine(GetPropertyOsdString("audio-device-list"));
|
||||
continue;
|
||||
}
|
||||
else if (arg == "--version")
|
||||
{
|
||||
Console.WriteLine(AppClass.About);
|
||||
continue;
|
||||
}
|
||||
else if (arg == "--input-keylist")
|
||||
{
|
||||
Console.WriteLine(GetPropertyString("input-key-list").Replace(",", BR));
|
||||
continue;
|
||||
}
|
||||
else if (arg.StartsWith("--command="))
|
||||
{
|
||||
Command(arg[10..]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!arg.Contains('='))
|
||||
public void ProcessCommandLineArgsPost()
|
||||
{
|
||||
if (arg.Contains("--no-"))
|
||||
foreach (var pair in CommandLine.Arguments)
|
||||
{
|
||||
arg = arg.Replace("--no-", "--");
|
||||
arg += "=no";
|
||||
}
|
||||
else
|
||||
arg += "=yes";
|
||||
}
|
||||
|
||||
string left = arg[2..arg.IndexOf("=")];
|
||||
string right = arg[(left.Length + 3)..];
|
||||
|
||||
if (string.IsNullOrEmpty(left))
|
||||
continue;
|
||||
|
||||
switch (left)
|
||||
if (pair.Name.EndsWith("-add"))
|
||||
{
|
||||
case "script": left = "scripts"; break;
|
||||
case "audio-file": left = "audio-files"; break;
|
||||
case "sub-file": left = "sub-files"; break;
|
||||
case "external-file": left = "external-files"; break;
|
||||
string name = pair.Name[..^4];
|
||||
string separator = name.Contains("-file") || name.Contains("-path") ? ";" : ",";
|
||||
SetPropertyString(name, GetPropertyString(name) + separator + pair.Value);
|
||||
}
|
||||
|
||||
App.CommandLineArguments[left] = right;
|
||||
|
||||
ProcessProperty(left, right);
|
||||
|
||||
if (!App.ProcessProperty(left, right))
|
||||
SetPropertyString(left, right);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -498,12 +457,6 @@ public class MainPlayer : MpvClient
|
||||
Command("playlist-shuffle");
|
||||
SetPropertyInt("playlist-pos", 0);
|
||||
}
|
||||
|
||||
if (files.Count == 0 || files[0].Contains("://"))
|
||||
{
|
||||
VideoSizeChanged?.Invoke(VideoSize);
|
||||
VideoSizeAutoResetEvent.Set();
|
||||
}
|
||||
}
|
||||
|
||||
public DateTime LastLoad;
|
||||
|
||||
7
src/MpvNet/Properties/launchSettings.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"profiles": {
|
||||
"MpvNet": {
|
||||
"commandName": "Project"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
namespace MpvNet.Windows;
|
||||
|
||||
namespace MpvNet;
|
||||
|
||||
public class StringPair
|
||||
{
|
||||
28
src/Setup/Inno/inno-setup.iss
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
#define MyAppName "mpv.net"
|
||||
#define MyAppExeName "mpvnet.exe"
|
||||
#define MyAppSourceDir "..\..\MpvNet.Windows\bin\Debug"
|
||||
#define MyAppVersion GetFileVersion("..\..\MpvNet.Windows\bin\Debug\mpvnet.exe")
|
||||
|
||||
[Setup]
|
||||
AppId={{9AA2B100-BEF3-44D0-B819-D8FC3C4D557D}}
|
||||
AppName={#MyAppName}
|
||||
AppVersion={#MyAppVersion}
|
||||
AppPublisher=Frank Skare (stax76)
|
||||
ArchitecturesInstallIn64BitMode=x64
|
||||
Compression=lzma2
|
||||
DefaultDirName={autopf}\{#MyAppName}
|
||||
OutputBaseFilename=mpv.net-v{#MyAppVersion}-setup
|
||||
OutputDir=E:\Desktop
|
||||
DefaultGroupName={#MyAppName}
|
||||
SetupIconFile=..\..\MpvNet.Windows\mpv-icon.ico
|
||||
UninstallDisplayIcon={app}\{#MyAppExeName}
|
||||
PrivilegesRequired=admin
|
||||
PrivilegesRequiredOverridesAllowed=dialog
|
||||
|
||||
[Icons]
|
||||
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
|
||||
|
||||
[Files]
|
||||
Source: "{#MyAppSourceDir}\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "{#MyAppSourceDir}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs;
|
||||