Compare commits

..

23 Commits

Author SHA1 Message Date
stax76
17e25619da Merge pull request #626 from nkh0472/patch-3
change screenshot-tag-colorspace default value to `yes`
2023-12-28 06:16:06 +01:00
stax76
a4376b1492 Merge pull request #627 from nkh0472/patch-4
Detailed description for hwdec
2023-12-28 06:13:37 +01:00
stax76
d41faad9d9 v7.0.0.5 Beta 2023-12-28 06:11:42 +01:00
nkh0472
0e6116b478 Detailed description for hwdec 2023-12-27 22:29:31 +08:00
nkh0472
789127e8ff change screenshot-tag-colorspace default value to yes 2023-12-27 22:17:45 +08:00
stax76
6ef9f32d4f misc 2023-12-26 16:58:12 +01:00
stax76
1048dbed40 New menu item and binding: File > Add files to playlist from clipboard (Ctrl+Shift+v) 2023-12-26 09:22:27 +01:00
stax76
86c823bfde misc 2023-12-24 07:34:12 +01:00
stax76
764f00ed3a misc 2023-12-23 10:20:57 +01:00
stax76
3e4ea03437 Support of the mpv option title-bar 2023-12-22 18:35:07 +01:00
stax76
0ef679e00d argh 2023-12-21 10:01:59 +01:00
stax76
7f2bf2e905 misc 2023-12-20 05:19:50 +01:00
stax76
ab8a8d5a35 Command line parser fix using list options with -add suffix 2023-12-19 12:12:34 +01:00
stax76
a3b9c653fa v7.0.0.4 Beta 2023-12-19 09:37:46 +01:00
stax76
ed48f5c559 Command line parser supports list options with -add suffix. Fixex #619. 2023-12-19 03:18:55 +01:00
stax76
d328f6b7ec Main window: Limited geometry support 2023-12-17 19:08:55 +01:00
stax76
16ba94d67d updated manual and new libplacebo GUI options 2023-12-16 13:48:27 +01:00
stax76
7978170133 Merge pull request #617 from FantasqueX/fix-typo-1
fix typo in changelog
2023-12-16 08:44:03 +01:00
stax76
ab313eb442 new libplacebo options 2023-12-16 08:43:22 +01:00
Letu Ren
f40008d94a fix typo in changelog 2023-12-16 15:31:50 +08:00
stax76
75e19d8d18 newly developed combo box control 2023-12-16 04:57:49 +01:00
stax76
9bb978f612 new combo box control 2023-12-16 04:52:16 +01:00
stax76
3af5b458ba misc 2023-12-15 14:58:32 +01:00
44 changed files with 3487 additions and 2217 deletions

View File

@@ -1,4 +1,43 @@
# v7.0.0.5 Beta (2023-12-28)
- Fix mpv.net option `language` not working from command line.
- Chinese and German translation updated.
- More libplacebo options added.
- Support of the mpv option `title-bar`.
- Video being less often rendered with black line at the bottom.
- The conf file reader/writer detects if the user prefers space before and after the equal sign.
- The portable download includes like the installer debug symbols.
- Setup questions on startup removed.
- Pressing shift while drag and drop appends instead of replaces
files in the playlist. mpv supports this as well.
- New menu item and binding: `File > Add files to playlist from clipboard` `Ctrl+Shift+v`.
- All list operation suffixes are available on the command line.
- Improved layout in conf editor.
- New zhongfly libmpv build.
# 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) # v7.0.0.3 Beta (2023-12-15)
- New conf editor option `Video/libplacebo/preset`. - New conf editor option `Video/libplacebo/preset`.
@@ -13,7 +52,8 @@
- Conf editor support added for the mpv options: - Conf editor support added for the mpv options:
`reset-on-next-file`, `input-ipc-server`, `background`, `title` `reset-on-next-file`, `input-ipc-server`, `background`, `title`
- Conf editor crash fixed. - 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. - 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) # v7.0.0.2 Beta (2023-12-13)
@@ -38,7 +78,7 @@
- Fix message box exceding working area size. - Fix message box exceding working area size.
- C# and PowerShell scripting was removed because of a compatibility problem - C# and PowerShell scripting was removed because of a compatibility problem
with the .NET 6 platform. .NET extensions are supported with a new host 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. - Redesigned bindings and context menu.
- auto-play option removed, mpv supports it with the option reset-on-next-file. - 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. - Dark mode title bar enabled on Windows 10.0.18985 or higher.

View File

@@ -25,6 +25,7 @@ Table of contents
* [Hidden Features](#hidden-features) * [Hidden Features](#hidden-features)
* [Differences compared to mpv](#differences-compared-to-mpv) * [Differences compared to mpv](#differences-compared-to-mpv)
* [Environment Variables](#environment-variables) * [Environment Variables](#environment-variables)
* [user-data](#user-data)
* [Context Menu Commands](#context-menu) * [Context Menu Commands](#context-menu)
@@ -43,9 +44,7 @@ Download
-------- --------
1. [Stable and beta portable and setup via GitHub download](../../../releases) 1. [Stable and beta portable and setup via GitHub download](../../../releases)
2. Stable via command line with winget: `winget install mpv.net`
2. Stable via command line from winget: `winget install mpv.net`
3. [Automated nightly portable builds](https://github.com/mpvnet-player/mpv.net/actions) 3. [Automated nightly portable builds](https://github.com/mpvnet-player/mpv.net/actions)
[Changelog](changelog.md) [Changelog](changelog.md)
@@ -54,10 +53,8 @@ Download
Installation Installation
------------ ------------
1. Windows 7 or higher is required (Windows 10 or higher is recommended). 1. Windows 10 or higher.
2. mpv.net since version 7.0 requires the 2. [.NET Desktop Runtime 6.0](https://dotnet.microsoft.com/en-us/download/dotnet/6.0)
[.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.
Internet streaming requires: Internet streaming requires:
@@ -69,8 +66,8 @@ Internet streaming requires:
File Associations can be registered using the context menu under 'Settings > Setup'. 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 After the file associations were registered, it might still be necessary to change the
default app in the Windows settings (Win+I, ms-settings:defaultapps). default app in the Windows settings.
Another way to register file associations is using Windows File Explorer, 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. select a media file and select 'Open with > Choose another app' in the context menu.
@@ -82,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 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. 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 Support
------- -------
@@ -90,14 +92,14 @@ Before making a support request, please try the newest [beta version](../../../r
Support can be requested here: Support can be requested here:
Beginner questions:
https://www.reddit.com/r/mpv
mpv.net bug reports, feature requests and advanced questions: mpv.net bug reports, feature requests and advanced questions:
https://github.com/mpvnet-player/mpv.net/issues https://github.com/mpvnet-player/mpv.net/issues
Beginner mpv questions:
https://www.reddit.com/r/mpv
Advanced mpv questions: Advanced mpv questions:
https://github.com/mpv-player/mpv/issues https://github.com/mpv-player/mpv/issues
@@ -108,8 +110,9 @@ Settings
mpv.net searches the config folder at: mpv.net searches the config folder at:
1. startup\portable_config 1. Folder defined via MPVNET_HOME environment variable.
2. %APPDATA%\mpv.net (`C:\Users\%USERNAME%\AppData\Roaming\mpv.net`) 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 options are stored in the file mpv.conf,
mpv.net options are stored in the file mpvnet.conf, mpv.net options are stored in the file mpvnet.conf,
@@ -119,7 +122,7 @@ mpv.net options are documented [here](#mpvnet-specific-options).
Input and context menu 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` The config folder can be opened from the context menu: `Settings > Open Config Folder`
@@ -139,24 +142,31 @@ mpv input options:
https://mpv.io/manual/master/#input https://mpv.io/manual/master/#input
Before version v7 all bindings and the context menu definition 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 in case it didn't exist. This had the disadvantage that mpv.net
lost control over all default bindings and the context menu lost control over all default bindings and context menu
defaults. This was unfortunate, v7 introduces a new design defaults. This was unfortunate, v7 introduces a new bindings
fixing it. and context menu design fixing it.
In v7 no input.conf file is created, the default bindings and In v7 no input.conf file is created, the default bindings and
context menu is defined internally. input.conf only contains context menu is defined internally. input.conf only contains
what is different from the internally defined defaults, 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 For backward compatibility the old input.conf context menu
menu definition using `#menu: ` is still supported. The new format with the menu definition using `#menu: ` is still
design also allows for a menu customization, in a sub section supported. The new design also allows for a menu customization,
called `Custom`. In input.conf it can be defined like so: in a sub section called `Custom`. In input.conf it can be
defined like so:
`Ctrl+a show-text Test #custom-menu: Test > Test` `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 Command Line Interface
---------------------- ----------------------
@@ -192,8 +202,6 @@ Terminal
When mpv.net is started from a terminal it will output status, 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. 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 mpv.net specific commands
------------------------- -------------------------
@@ -205,6 +213,9 @@ mpv.net commands are used when mpv commands don't exist or lack a feature.
### add-to-path ### add-to-path
Adds mpv.net to the Path environment variable. 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 ### load-audio
Shows a file browser dialog to open external audio files. Shows a file browser dialog to open external audio files.
@@ -230,10 +241,13 @@ Shows a folder browser dialog to open a DVD or BD folder.
ISO images don't have to be mounted, but instead can be ISO images don't have to be mounted, but instead can be
opened directly with the open-files command. opened directly with the open-files command.
### open-clipboard ### open-clipboard [\<flags\>]
Opens a single URL or filepath from the clipboard, Opens a single URL or filepath from the clipboard,
or multiple files in the file clipboard format. or multiple files in the file clipboard format.
**append**
Appends files/URLs to the playlist.
### play-pause ### play-pause
Cycles the pause property. In case the playlist is empty, Cycles the pause property. In case the playlist is empty,
the most recent file from the recent files list is loaded. the most recent file from the recent files list is loaded.
@@ -259,12 +273,6 @@ Shows available [mpv input commands](https://mpv.io/manual/master/#list-of-input
### show-conf-editor ### show-conf-editor
Shows the conf editor. Shows the conf editor.
### show-decoders
Shows available decoders.
### show-demuxers
Shows available demuxers.
### show-input-editor ### show-input-editor
Shows the input editor. Shows the input editor.
@@ -513,7 +521,8 @@ Scripting
#### Lua #### 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). 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).
@@ -522,10 +531,10 @@ Lua scripting is documented in the mpv.net wiki [here](https://github.com/mpvnet
[mpv JavaScript documentation](https://mpv.io/manual/master/#javascript) [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: the filename must have the same name as the directory:
```Text ```Text
@@ -597,7 +606,7 @@ visible, even when mpv.net is started from the terminal and music is played.
For mpv.net it's currently not possible to find out where OSC menus are located, For mpv.net it's currently not possible to find out where OSC menus are located,
but there are 3 features that require this information, therefore mpv.net but there are 3 features that require this information, therefore mpv.net
makes the assumption that near the window borders might be OSC menus. As a result makes the assumption that near the window borders might be OSC menus. As a result
the following three features, work only when invokes from the center of the window: the following three features, work only when invoked from the center of the window:
1. Window dragging (moving the window with the mouse). 1. Window dragging (moving the window with the mouse).
2. Showing the context menu. 2. Showing the context menu.
@@ -619,20 +628,42 @@ https://mpv.io/manual/master/#window
- [ontop](https://mpv.io/manual/master/#options-ontop) - [ontop](https://mpv.io/manual/master/#options-ontop)
- [screen](https://mpv.io/manual/master/#options-screen) - [screen](https://mpv.io/manual/master/#options-screen)
- [snap-window](https://mpv.io/manual/master/#options-snap-window) - [snap-window](https://mpv.io/manual/master/#options-snap-window)
- [title-bar](https://mpv.io/manual/master/#options-title-bar)
- [title](https://mpv.io/manual/master/#options-title) - [title](https://mpv.io/manual/master/#options-title)
- [window-maximized](https://mpv.io/manual/master/#options-window-maximized) - [window-maximized](https://mpv.io/manual/master/#options-window-maximized)
- [window-minimized](https://mpv.io/manual/master/#options-window-minimized) - [window-minimized](https://mpv.io/manual/master/#options-window-minimized)
- [window-scale](https://mpv.io/manual/master/#options-window-scale) - [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) #### --autofit=\<int\>
Supported is a single integer value in the range 0-100.
- [autofit-smaller](https://mpv.io/manual/master/#options-autofit-smaller) \<int\> Initial window height in percent. Default: 60
Supported is a single integer value in the range 0-100.
- [autofit](https://mpv.io/manual/master/#options-autofit) #### --autofit-smaller=\<int\>
Supported is a single integer value in the range 0-100.
\<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.
#### --title-bar=\<yes|no\>
Shows the window title bar. Default: yes
**mpv.net specific window features:**
mpv.net specific window features are documented in the [screen section](#screen). mpv.net specific window features are documented in the [screen section](#screen).
@@ -677,10 +708,18 @@ Environment Variables
Directory where mpv.net looks for user settings. 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 Context Menu Commands
--------------------- ---------------------
@@ -699,8 +738,8 @@ Blu-ray and DVD ISO image files are supported.
### Open > Open URL or file path from clipboard ### Open > Open URL or file path from clipboard
Opens files and URLs from the clipboard. How to open URLs directly Opens files and URLs from the clipboard. Shift key appends to the playlist.
from the browser from sites like YouTube is described in the How to open URLs directly from the browser from sites like YouTube is described in the
[External Tools section](#external-tools). [External Tools section](#external-tools).

View File

@@ -1,4 +1,6 @@
$ErrorActionPreference = 'Stop'
$PoFiles = Get-ChildItem $PSScriptRoot/po $PoFiles = Get-ChildItem $PSScriptRoot/po
$ExeFolder = "$PSScriptRoot/../src/MpvNet.Windows/bin/Debug" $ExeFolder = "$PSScriptRoot/../src/MpvNet.Windows/bin/Debug"
@@ -20,15 +22,14 @@ function CreateFolder
foreach ($it in $PoFiles) foreach ($it in $PoFiles)
{ {
$folder = "$ExeFolder/Locale/$($it.BaseName)/LC_MESSAGES" $folder = "$ExeFolder/Locale/$($it.BaseName)/LC_MESSAGES"
New-Item -ItemType Directory -Path $folder
$moPath = "$folder/mpvnet.mo"
New-Item -ItemType File -Path $moPath
msgfmt --output-file=$moPath $it.FullName
if ($LASTEXITCODE -ne 0) if (-not (Test-Path $folder))
{ {
throw New-Item -ItemType Directory -Path $folder
} }
$moPath = "$folder/mpvnet.mo"
msgfmt --output-file=$moPath $it.FullName
if ($LastExitCode) { throw $LastExitCode }
$moPath $moPath
} }

View File

@@ -3,6 +3,7 @@ D:\Projects\CS\mpv.net\src\MpvNet\AppInfo.cs
D:\Projects\CS\mpv.net\src\MpvNet\Binding.cs D:\Projects\CS\mpv.net\src\MpvNet\Binding.cs
D:\Projects\CS\mpv.net\src\MpvNet\Chapter.cs D:\Projects\CS\mpv.net\src\MpvNet\Chapter.cs
D:\Projects\CS\mpv.net\src\MpvNet\Command.cs D:\Projects\CS\mpv.net\src\MpvNet\Command.cs
D:\Projects\CS\mpv.net\src\MpvNet\CommandLine.cs
D:\Projects\CS\mpv.net\src\MpvNet\ExtensionLoader.cs D:\Projects\CS\mpv.net\src\MpvNet\ExtensionLoader.cs
D:\Projects\CS\mpv.net\src\MpvNet\FileTypes.cs D:\Projects\CS\mpv.net\src\MpvNet\FileTypes.cs
D:\Projects\CS\mpv.net\src\MpvNet\Folder.cs D:\Projects\CS\mpv.net\src\MpvNet\Folder.cs
@@ -14,6 +15,7 @@ D:\Projects\CS\mpv.net\src\MpvNet\MediaTrack.cs
D:\Projects\CS\mpv.net\src\MpvNet\MpvClient.cs D:\Projects\CS\mpv.net\src\MpvNet\MpvClient.cs
D:\Projects\CS\mpv.net\src\MpvNet\Player.cs D:\Projects\CS\mpv.net\src\MpvNet\Player.cs
D:\Projects\CS\mpv.net\src\MpvNet\Settings.cs D:\Projects\CS\mpv.net\src\MpvNet\Settings.cs
D:\Projects\CS\mpv.net\src\MpvNet\StringPair.cs
D:\Projects\CS\mpv.net\src\MpvNet\Terminal.cs D:\Projects\CS\mpv.net\src\MpvNet\Terminal.cs
D:\Projects\CS\mpv.net\src\MpvNet\Translator.cs D:\Projects\CS\mpv.net\src\MpvNet\Translator.cs
D:\Projects\CS\mpv.net\src\MpvNet\ExtensionMethod\ObjectExtension.cs D:\Projects\CS\mpv.net\src\MpvNet\ExtensionMethod\ObjectExtension.cs
@@ -35,9 +37,8 @@ D:\Projects\CS\mpv.net\src\MpvNet.Windows\GlobalUsings.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\Program.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\Program.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\Settings.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\Settings.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\StringPair.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\Help\RegistryHelp.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\Help\RegistryHelp.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\Help\WinMpvHelp.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\Help\WinApiHelp.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\Native\StockIcon.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\Native\StockIcon.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\Native\Taskbar.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\Native\Taskbar.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\Native\WinApi.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\Native\WinApi.cs
@@ -51,6 +52,7 @@ D:\Projects\CS\mpv.net\src\MpvNet.Windows\WinForms\MainForm.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WinForms\MainForm.Designer.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\WinForms\MainForm.Designer.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WinForms\SnapManager.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\WinForms\SnapManager.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\BindingProxy.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\BindingProxy.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\ComboBoxTemplateSelector.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\ConfWindow.xaml.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\ConfWindow.xaml.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\InputWindow.xaml.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\InputWindow.xaml.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\ISettingControl.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\ISettingControl.cs
@@ -59,6 +61,7 @@ D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\MenuHelp.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\Msg.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\Msg.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\WpfApplication.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\WpfApplication.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\WpfTranslator.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\WpfTranslator.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\Controls\ComboBoxSettingControl.xaml.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\Controls\CommandPaletteControl.xaml.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\Controls\CommandPaletteControl.xaml.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\Controls\HyperlinkEx.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\Controls\HyperlinkEx.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\Controls\OptionSettingControl.xaml.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\Controls\OptionSettingControl.xaml.cs

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,6 @@
$ErrorActionPreference = 'Stop'
# Write list of .cs files into cs-files.txt file # Write list of .cs files into cs-files.txt file
Get-ChildItem $PSScriptRoot/.. -Recurse -File -Filter '*.cs' | Get-ChildItem $PSScriptRoot/.. -Recurse -File -Filter '*.cs' |
Where-Object { $_ -notmatch '[/\\]obj[/\\]' } | Where-Object { $_ -notmatch '[/\\]obj[/\\]' } |
@@ -7,6 +9,7 @@ Get-ChildItem $PSScriptRoot/.. -Recurse -File -Filter '*.cs' |
# Create .pot file # Create .pot file
xgettext --force-po --from-code=UTF-8 '--language=c#' -o $PSScriptRoot/source.pot --files-from=$PSScriptRoot/cs-files.txt --keyword=_ xgettext --force-po --from-code=UTF-8 '--language=c#' -o $PSScriptRoot/source.pot --files-from=$PSScriptRoot/cs-files.txt --keyword=_
if ($LastExitCode) { throw $LastExitCode }
# Backup .po files # Backup .po files
$BackupTargetFolder = $env:TEMP + '/mpv.net po backup ' + (Get-Date -Format 'yyyy-MM-dd HH_mm_ss') $BackupTargetFolder = $env:TEMP + '/mpv.net po backup ' + (Get-Date -Format 'yyyy-MM-dd HH_mm_ss')
@@ -16,3 +19,5 @@ Copy-Item $PSScriptRoot/po $BackupTargetFolder -Force -Recurse
# Update .po files # Update .po files
(Get-ChildItem $PSScriptRoot/PO -Filter '*.po').FullName | (Get-ChildItem $PSScriptRoot/PO -Filter '*.po').FullName |
ForEach-Object { msgmerge --sort-output --backup=none --update $_ $PSScriptRoot/source.pot } ForEach-Object { msgmerge --sort-output --backup=none --update $_ $PSScriptRoot/source.pot }
if ($LastExitCode) { throw $LastExitCode }

View File

@@ -53,6 +53,7 @@ public class Conf
if (section.HasName("help")) baseSetting.Help = section.GetValue("help"); if (section.HasName("help")) baseSetting.Help = section.GetValue("help");
if (section.HasName("url")) baseSetting.URL = section.GetValue("url"); if (section.HasName("url")) baseSetting.URL = section.GetValue("url");
if (section.HasName("width")) baseSetting.Width = Convert.ToInt32(section.GetValue("width")); 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 (section.HasName("type")) baseSetting.Type = section.GetValue("type");
if (baseSetting.Help.ContainsEx("\\n")) if (baseSetting.Help.ContainsEx("\\n"))

View File

@@ -153,10 +153,15 @@ public class GuiCommand
public void OpenFromClipboard(IList<string> args) public void OpenFromClipboard(IList<string> args)
{ {
bool append = args.Count == 1 && args[0] == "append";
if (System.Windows.Forms.Clipboard.ContainsFileDropList()) if (System.Windows.Forms.Clipboard.ContainsFileDropList())
{ {
string[] files = System.Windows.Forms.Clipboard.GetFileDropList().Cast<string>().ToArray(); string[] files = System.Windows.Forms.Clipboard.GetFileDropList().Cast<string>().ToArray();
Player.LoadFiles(files, false, false); Player.LoadFiles(files, false, append);
if (append)
Player.CommandV("show-text", _("Files/URLs were added to the playlist"));
} }
else else
{ {
@@ -169,11 +174,14 @@ public class GuiCommand
if (files.Count == 0) if (files.Count == 0)
{ {
Terminal.WriteError("The clipboard does not contain a valid URL or file."); Terminal.WriteError(_("The clipboard does not contain a valid URL or file."));
return; return;
} }
Player.LoadFiles(files.ToArray(), false, false); Player.LoadFiles(files.ToArray(), false, append);
if (append)
Player.CommandV("show-text", _("Files/URLs were added to the playlist"));
} }
} }
@@ -322,7 +330,7 @@ public class GuiCommand
if (path.ToLower().Contains(Folder.Startup.TrimEnd(Path.DirectorySeparatorChar).ToLower())) if (path.ToLower().Contains(Folder.Startup.TrimEnd(Path.DirectorySeparatorChar).ToLower()))
{ {
Msg.ShowWarning("mpv.net is already in Path."); Msg.ShowWarning(_("mpv.net is already in Path."));
return; return;
} }
@@ -330,7 +338,7 @@ public class GuiCommand
Folder.Startup.TrimEnd(Path.DirectorySeparatorChar) + ";" + path, Folder.Startup.TrimEnd(Path.DirectorySeparatorChar) + ";" + path,
EnvironmentVariableTarget.User); EnvironmentVariableTarget.User);
Msg.ShowInfo("mpv.net successfully was added to Path."); Msg.ShowInfo(_("mpv.net was successfully added to Path."));
} }
public void ShowPlaylist() public void ShowPlaylist()

View File

@@ -7,7 +7,7 @@ using static MpvNet.Windows.Native.WinApi;
namespace MpvNet.Windows.Help; namespace MpvNet.Windows.Help;
public class WinApiHelp public static class WinApiHelp
{ {
public static Version WindowsTen1607 { get; } = new Version(10, 0, 14393); // Windows 10 1607 public static Version WindowsTen1607 { get; } = new Version(10, 0, 14393); // Windows 10 1607
@@ -27,31 +27,51 @@ public class WinApiHelp
} }
} }
public static void SubtractWindowBorders(IntPtr hwnd, ref Rect rc, int dpi) public static void AdjustWindowRect(IntPtr hwnd, ref RECT rc, int dpi)
{ {
Rect r = new Rect(0, 0, 0, 0); uint style = (uint)GetWindowLongPtr(hwnd, -16); // GWL_STYLE
AddWindowBorders(hwnd, ref r, dpi); uint styleEx = (uint)GetWindowLongPtr(hwnd, -20); // GWL_EXSTYLE
if (Environment.OSVersion.Version >= WindowsTen1607)
AdjustWindowRectExForDpi(ref rc, style, false, styleEx, (uint)dpi);
else
Native.WinApi.AdjustWindowRect(ref rc, style, false);
}
public static void AddWindowBorders(IntPtr hwnd, ref RECT rc, int dpi, bool changeTop)
{
RECT win = rc;
AdjustWindowRect(hwnd, ref rc, dpi);
if (changeTop)
{
int top = rc.Top;
top -= rc.Top - win.Top;
rc = new RECT(rc.Left, top, rc.Right, rc.Bottom);
}
}
public static void SubtractWindowBorders(IntPtr hwnd, ref RECT rc, int dpi, bool changeTop)
{
RECT r = new RECT();
AddWindowBorders(hwnd, ref r, dpi, changeTop);
rc.Left -= r.Left; rc.Left -= r.Left;
rc.Top -= r.Top; rc.Top -= r.Top;
rc.Right -= r.Right; rc.Right -= r.Right;
rc.Bottom -= r.Bottom; rc.Bottom -= r.Bottom;
} }
public static void AddWindowBorders(IntPtr hwnd, ref Rect rc, int dpi) public static int GetTitleBarHeight(IntPtr hwnd, int dpi)
{ {
uint windowStyle = (uint)GetWindowLong(hwnd, -16); // GWL_STYLE RECT rect = new RECT();
uint windowStyleEx = (uint)GetWindowLong(hwnd, -20); // GWL_EXSTYLE AdjustWindowRect(hwnd, ref rect, dpi);
return -rect.Top;
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) public static Rectangle GetWorkingArea(IntPtr handle, Rectangle workingArea)
{ {
if (handle != IntPtr.Zero && GetDwmWindowRect(handle, out Rect dwmRect) && if (handle != IntPtr.Zero && GetDwmWindowRect(handle, out RECT dwmRect) &&
GetWindowRect(handle, out Rect rect)) GetWindowRect(handle, out RECT rect))
{ {
int left = workingArea.Left; int left = workingArea.Left;
int top = workingArea.Top; int top = workingArea.Top;
@@ -69,28 +89,12 @@ public class WinApiHelp
return workingArea; return workingArea;
} }
public static bool GetDwmWindowRect(IntPtr handle, out Rect rect) public static bool GetDwmWindowRect(IntPtr handle, out RECT rect)
{ {
const uint DWMWA_EXTENDED_FRAME_BOUNDS = 9; const uint DWMWA_EXTENDED_FRAME_BOUNDS = 9;
return 0 == DwmGetWindowAttribute(handle, DWMWA_EXTENDED_FRAME_BOUNDS, return 0 == DwmGetWindowAttribute(handle, DWMWA_EXTENDED_FRAME_BOUNDS,
out rect, (uint)Marshal.SizeOf<Rect>()); 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) public static string GetAppPathForExtension(params string[] extensions)

View File

@@ -1,36 +0,0 @@

using System.Windows;
using MpvNet.Windows.WPF;
namespace MpvNet.Windows.Help;
public class WinMpvHelp
{
public static void AddToPath()
{
string path = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.User)!;
if (path.ToLower().Contains(Folder.Startup.TrimEnd(Path.DirectorySeparatorChar).ToLower()))
return;
string dir = RegistryHelp.GetString("PathEnvVarCheck");
if (dir == Folder.Startup)
return;
var result = Msg.ShowQuestion("Would you like to add mpv.net to the Path environment variable?",
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.");
}
RegistryHelp.SetString("PathEnvVarCheck", Folder.Startup);
}
}

View File

@@ -11,9 +11,9 @@
<UseWindowsForms>true</UseWindowsForms> <UseWindowsForms>true</UseWindowsForms>
<ApplicationIcon>mpv-icon.ico</ApplicationIcon> <ApplicationIcon>mpv-icon.ico</ApplicationIcon>
<Product>mpv.net</Product> <Product>mpv.net</Product>
<FileVersion>7.0.0.3</FileVersion> <FileVersion>7.0.0.5</FileVersion>
<AssemblyVersion>7.0.0.3</AssemblyVersion> <AssemblyVersion>7.0.0.5</AssemblyVersion>
<InformationalVersion>7.0.0.3</InformationalVersion> <InformationalVersion>7.0.0.5</InformationalVersion>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>

View File

@@ -2,6 +2,7 @@
using System.Drawing; using System.Drawing;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using static HandyControl.Tools.Interop.InteropValues;
namespace MpvNet.Windows.Native; namespace MpvNet.Windows.Native;
@@ -20,7 +21,7 @@ public static class WinApi
public static extern uint ActivateKeyboardLayout(IntPtr hkl, uint flags); public static extern uint ActivateKeyboardLayout(IntPtr hkl, uint flags);
[DllImport("user32.dll")] [DllImport("user32.dll")]
public static extern bool GetWindowRect(IntPtr hwnd, out Rect lpRect); public static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);
[DllImport("user32.dll", CharSet = CharSet.Unicode)] [DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindowEx( public static extern IntPtr FindWindowEx(
@@ -48,28 +49,19 @@ public static class WinApi
public static extern int GetDpiForWindow(IntPtr hwnd); public static extern int GetDpiForWindow(IntPtr hwnd);
[DllImport("user32.dll")] [DllImport("user32.dll")]
public static extern bool AdjustWindowRect(ref Rect lpRect, uint dwStyle, bool bMenu); public static extern bool AdjustWindowRect(ref RECT lpRect, uint dwStyle, bool bMenu);
[DllImport("user32.dll")] [DllImport("user32.dll")]
public static extern bool AdjustWindowRectExForDpi( public static extern bool AdjustWindowRectExForDpi(
ref Rect lpRect, uint dwStyle, bool bMenu, uint dwExStyle, uint dpi); ref RECT lpRect, uint dwStyle, bool bMenu, uint dwExStyle, uint dpi);
[DllImport("user32.dll")] [DllImport("user32.dll")]
public static extern bool SetWindowPos( public static extern bool SetWindowPos(
IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags); IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags);
[DllImport("user32.dll", EntryPoint = "GetWindowLong")]
public static extern IntPtr GetWindowLong32(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")] [DllImport("user32.dll")]
public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int 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);
[DllImport("user32.dll")]
public static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, uint dwNewLong);
[DllImport("gdi32.dll")] [DllImport("gdi32.dll")]
public static extern int GetDeviceCaps(IntPtr hdc, int nIndex); public static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
@@ -79,17 +71,17 @@ public static class WinApi
[DllImport("dwmapi.dll")] [DllImport("dwmapi.dll")]
public static extern int DwmGetWindowAttribute( public static extern int DwmGetWindowAttribute(
IntPtr hwnd, uint dwAttribute, out Rect pvAttribute, uint cbAttribute); IntPtr hwnd, uint dwAttribute, out RECT pvAttribute, uint cbAttribute);
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct Rect public struct RECT
{ {
public int Left; public int Left;
public int Top; public int Top;
public int Right; public int Right;
public int Bottom; public int Bottom;
public Rect(Rectangle r) public RECT(Rectangle r)
{ {
Left = r.Left; Left = r.Left;
Top = r.Top; Top = r.Top;
@@ -97,7 +89,7 @@ public static class WinApi
Bottom = r.Bottom; Bottom = r.Bottom;
} }
public Rect(int left, int top, int right, int bottom) public RECT(int left, int top, int right, int bottom)
{ {
Left = left; Left = left;
Top = top; Top = top;
@@ -110,9 +102,9 @@ public static class WinApi
public int Width => Right - Left; public int Width => Right - Left;
public int Height => Bottom - Top; public int Height => Bottom - Top;
public static Rect FromRectangle(Rectangle rect) public static RECT FromRectangle(Rectangle rect)
{ {
return new Rect(rect.X, rect.Y, rect.X + rect.Width, rect.Y + rect.Height); return new RECT(rect.X, rect.Y, rect.X + rect.Width, rect.Y + rect.Height);
} }
public override string ToString() public override string ToString()
@@ -121,6 +113,20 @@ public static class WinApi
} }
} }
[StructLayout(LayoutKind.Sequential)]
public struct NCCALCSIZE_PARAMS
{
public NCCALCSIZE_PARAMS(RECT[] r, WINDOWPOS wp)
{
rgrc = r;
lppos = wp;
}
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public RECT[] rgrc;
public WINDOWPOS lppos;
}
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct CopyDataStruct public struct CopyDataStruct
{ {

View File

@@ -7,7 +7,6 @@ using MpvNet.Help;
using MpvNet.Windows.UI; using MpvNet.Windows.UI;
using MpvNet.Windows.Help; using MpvNet.Windows.Help;
using MpvNet.Windows.WPF; using MpvNet.Windows.WPF;
using System.Diagnostics;
namespace MpvNet.Windows; namespace MpvNet.Windows;
@@ -42,7 +41,7 @@ static class Program
Theme.Init(); Theme.Init();
Mutex mutex = new Mutex(true, StringHelp.GetMD5Hash(App.ConfPath), out bool isFirst); Mutex mutex = new Mutex(true, StringHelp.GetMD5Hash(App.ConfPath), out bool isFirst);
if (Control.ModifierKeys.HasFlag(Keys.Shift) || if (Control.ModifierKeys == Keys.Shift ||
App.CommandLine.Contains("--process-instance=multi") || App.CommandLine.Contains("--process-instance=multi") ||
App.CommandLine.Contains("--o=")) App.CommandLine.Contains("--o="))
{ {
@@ -97,10 +96,13 @@ static class Program
return; return;
} }
if (App.CommandLine.Contains("--o=")) if (ProcessCommandLineArguments())
Environment.GetCommandLineArgs();
else if (App.CommandLine.Contains("--o="))
{ {
App.AutoLoadFolder = false; App.AutoLoadFolder = false;
Player.Init(IntPtr.Zero); Player.Init(IntPtr.Zero);
Player.ProcessCommandLineArgsPost();
Player.ProcessCommandLineFiles(); Player.ProcessCommandLineFiles();
Player.SetPropertyString("idle", "no"); Player.SetPropertyString("idle", "no");
Player.EventLoop(); Player.EventLoop();
@@ -119,4 +121,48 @@ static class Program
Terminal.WriteError(ex); 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;
}
} }

View File

@@ -0,0 +1,7 @@
{
"profiles": {
"MpvNet.Windows": {
"commandName": "Project"
}
}
}

View File

@@ -3,7 +3,7 @@ name = process-instance
file = mpvnet file = mpvnet
default = single default = single
directory = General 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 = multi Create a new process everytime the shell starts mpv.net
option = single Force a single 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 option = queue Force a single process and add files to playlist
@@ -17,7 +17,7 @@ name = media-info
file = mpvnet file = mpvnet
default = yes default = yes
directory = General directory = General
help = Usage of the media info library instead of mpv to access media information. (mpv.net option) help = Usage of the media info library instead of mpv to retrieve media information. (mpv.net option)
option = yes option = yes
option = no option = no
@@ -44,6 +44,21 @@ file = mpvnet
directory = General directory = General
help = Used menu syntax for defining the context menu in input.conf.\nmpv.net by default uses '#menu:', uosc uses '#!' by default. 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 name = debug-mode
file = mpvnet file = mpvnet
default = no default = no
@@ -67,26 +82,26 @@ file = mpv
default = no default = no
directory = Video directory = Video
url = https://mpv.io/manual/master/#options-hwdec url = https://mpv.io/manual/master/#options-hwdec
help = Specify the hardware video decoding API that should be used if possible. Whether hardware decoding is actually done depends on the video codec. If hardware decoding is not possible, mpv will fall back on software decoding.\n\nFor more information visit: help = Specify the hardware video decoding API that should be used if possible. Whether hardware decoding is actually done depends on the video codec. If hardware decoding is not possible, mpv will fall back on software decoding. Hardware decoding is disabled by default to maintain reliability. However, modern hardware should supports hardware video decoding, reducing CPU usage and power consumption.\n\nFor more information visit:
option = no always use software decoding option = no always use software decoding
option = auto enable best hw decoder option = auto enable best hw decoder
option = yes exactly the same as auto option = yes exactly the same as auto
option = auto-copy enable best hw decoder with copy-back option = auto-copy enable best hw decoder with copy-back
option = auto-safe enable any whitelisted hw decoder 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 requires vo=gpu with gpu-context=d3d11, gpu-context=angle or gpu-context=dxinterop
option = dxva2-copy copies video back to system RAM (Windows only) option = dxva2-copy copies video back to system RAM
option = d3d11va requires vo=gpu with gpu-context=d3d11 or gpu-context=angle (Windows 8+ only) option = d3d11va requires vo=gpu with gpu-context=d3d11 or gpu-context=angle
option = d3d11va-copy copies video back to system RAM (Windows 8+ only) option = d3d11va-copy copies video back to system RAM
option = cuda requires vo=gpu (Any platform CUDA is available) 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 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 name = gpu-api
file = mpv file = mpv
default = auto default = auto
directory = Video directory = Video/Render Options
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. 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 = auto Use any available API
option = d3d11 Allow only gpu-context=d3d11 option = d3d11 Allow only gpu-context=d3d11
option = opengl Allow only OpenGL (requires OpenGL 2.1+ or GLES 2.0+) option = opengl Allow only OpenGL (requires OpenGL 2.1+ or GLES 2.0+)
@@ -95,7 +110,7 @@ option = vulkan Allow only Vulkan
name = gpu-context name = gpu-context
file = mpv file = mpv
default = auto default = auto
directory = Video directory = Video/Render Options
option = auto auto-select option = auto auto-select
option = d3d11 Win32, with native Direct3D 11 rendering. 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). 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).
@@ -103,67 +118,63 @@ 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 = 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 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 = 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 = scale name = scale
file = mpv file = mpv
default = bilinear default = lanczos
directory = Video/Render Options 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 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). url = https://mpv.io/manual/master/#options-scale
option = spline36 Mid quality and speed. This is the default when using gpu-hq. option = bilinear
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 = spline36
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 = lanczos
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 = ewa_lanczos
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 = ewa_lanczossharp
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). option = mitchell
option = oversample
name = cscale name = cscale
file = mpv file = mpv
default = bilinear default = bilinear
directory = Video/Render Options directory = Video/Render Options/Scaling
help = As scale, but for interpolating chroma information. If the image is not subsampled, this option is ignored entirely. 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). url = https://mpv.io/manual/master/#options-cscale
option = spline36 Mid quality and speed. This is the default when using gpu-hq. option = bilinear
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 = spline36
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 = lanczos
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 = ewa_lanczos
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 = ewa_lanczossharp
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). option = mitchell
option = oversample
name = dscale name = dscale
file = mpv file = mpv
default = default = lanczos
directory = Video/Render Options 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. 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). url = https://mpv.io/manual/master/#options-dscale
option = spline36 Mid quality and speed. This is the default when using gpu-hq. option = bilinear
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 = spline36
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 = lanczos
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 = ewa_lanczos
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 = ewa_lanczossharp
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). option = mitchell
option = oversample
name = correct-downscaling
file = mpv
default = no
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
name = sigmoid-upscaling
file = mpv
default = no
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 name = dither-depth
file = mpv file = mpv
@@ -175,22 +186,6 @@ option = auto Automatic selection. If output bit depth cannot be detected, 8 bi
option = 8 Dither to 8 bit output. option = 8 Dither to 8 bit output.
option = 10 Dither to 10 bit output. option = 10 Dither to 10 bit output.
name = correct-downscaling
file = mpv
default = no
directory = Video/Render Options
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
name = sigmoid-upscaling
file = mpv
default = no
directory = Video/Render Options
help = When upscaling, use a sigmoidal color transform to avoid emphasizing ringing artifacts. This also implies linear-scaling.
option = yes
option = no
name = deband name = deband
file = mpv file = mpv
default = no default = no
@@ -203,7 +198,7 @@ name = hdr-compute-peak
file = mpv file = mpv
default = auto default = auto
directory = Video/Render Options directory = Video/Render Options
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. url = https://mpv.io/manual/master/#options-hdr-compute-peak
option = auto option = auto
option = yes option = yes
option = no option = no
@@ -212,7 +207,15 @@ name = allow-delayed-peak-detect
file = mpv file = mpv
default = yes default = yes
directory = Video/Render Options directory = Video/Render Options
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.) 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 = yes
option = no option = no
@@ -239,10 +242,10 @@ option = high_quality Reset all everything to high quality presets (where avail
name = upscaler name = upscaler
file = libplacebo file = libplacebo
directory = Video/libplacebo/Scaling directory = Video/libplacebo/Scaling
default = default default = lanczos
help = Sets the filter used for upscaling. Defaults to lanczos. help = Sets the filter used for upscaling.
url = https://libplacebo.org/options/#upscalerfilter url = https://libplacebo.org/options/#upscalerfilter
option = default Default. option-name-width = 135
option = none No filter, only use basic GPU texture sampling. option = none No filter, only use basic GPU texture sampling.
option = nearest Nearest-neighbour (box) sampling (very fast). option = nearest Nearest-neighbour (box) sampling (very fast).
option = bilinear Bilinear sampling (very fast). option = bilinear Bilinear sampling (very fast).
@@ -255,12 +258,484 @@ option = ewa_lanczos EWA Lanczos ("Jinc") reconstruction (slow).
option = ewa_lanczossharp Sharpened version of ewa_lanczos (slow). option = ewa_lanczossharp Sharpened version of ewa_lanczos (slow).
option = ewa_lanczos4sharpest Very sharp version of ewa_lanczos, with anti-ringing (very 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_preset
file = libplacebo
directory = Video/libplacebo/Debanding
help = Overrides the value of all options in this section by their default values from the given preset.
default = none
option = none
option = default
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_preset
file = libplacebo
directory = Video/libplacebo/Sigmoidization
help = Overrides the value of all options in this section by their default values from the given preset.
default = none
option = none
option = default
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 = color_adjustment
file = libplacebo
directory = Video/libplacebo/Color Adjustment
help = Enables color adjustment.
default = yes
option = yes
option = no
name = color_adjustment_preset
file = libplacebo
directory = Video/libplacebo/Color Adjustment
help = Overrides the value of all options in this section by their default values from the given preset.
default = none
option = none
option = neutral
name = brightness
file = libplacebo
directory = Video/libplacebo/Color Adjustment
help = <-1.0..1.0> Brightness boost. Adds a constant bias onto the source luminance signal. 0.0 = neutral, 1.0 = solid white, -1.0 = solid black. Defaults to 0.0.
name = contrast
file = libplacebo
directory = Video/libplacebo/Color Adjustment
help = <0.0..100.0> Contrast gain. Multiplies the source luminance signal by a constant factor. 1.0 = neutral, 0.0 = solid black. Defaults to 1.0.
name = saturation
file = libplacebo
directory = Video/libplacebo/Color Adjustment
help = <0.0..100.0> Saturation gain. Multiplies the source chromaticity signal by a constant factor. 1.0 = neutral, 0.0 = grayscale. Defaults to 1.0.
name = hue
file = libplacebo
directory = Video/libplacebo/Color Adjustment
help = <angle> Hue shift. Corresponds to a rotation of the UV subvector around the neutral axis. Specified in radians. Defaults to 0.0 (neutral).
name = gamma
file = libplacebo
directory = Video/libplacebo/Color Adjustment
help = <0.0..100.0> Gamma lift. Subjectively brightnes or darkens the scene while preserving overall contrast. 1.0 = neutral, 0.0 = solid black. Defaults to 1.0.
name = temperature
file = libplacebo
directory = Video/libplacebo/Color Adjustment
help = <-1.143..5.286> Color temperature shift. Relative to 6500 K, a value of 0.0 gives you 6500 K (no change), a value of -1.0 gives you 3000 K, and a value of 1.0 gives you 10000 K. Defaults to 0.0.
name = peak_detect
file = libplacebo
directory = Video/libplacebo/HDR Peak Detection
help = Enables HDR peak detection.
default = yes
option = yes
option = no
name = peak_detection_preset
file = libplacebo
directory = Video/libplacebo/HDR Peak Detection
help = Overrides the value of all options in this section by their default values from the given preset. high_quality also enables frame histogram measurement.
default = none
option = none
option = default
option = high_quality
name = peak_smoothing_period
file = libplacebo
directory = Video/libplacebo/HDR Peak Detection
help = <0.0..1000.0> Smoothing coefficient for the detected values.
url = https://libplacebo.org/options/#peak_smoothing_period0010000
name = scene_threshold_low
file = libplacebo
directory = Video/libplacebo/HDR Peak Detection
url = https://libplacebo.org/options/#scene_threshold_low001000-scene_threshold_high001000
name = scene_threshold_high
file = libplacebo
directory = Video/libplacebo/HDR Peak Detection
url = https://libplacebo.org/options/#scene_threshold_low001000-scene_threshold_high001000
name = peak_percentile
file = libplacebo
directory = Video/libplacebo/HDR Peak Detection
help = <0.0..100.0> Which percentile of the input image brightness histogram to consider as the true peak of the scene.
url = https://libplacebo.org/options/#peak_percentile001000
name = black_cutoff
file = libplacebo
directory = Video/libplacebo/HDR Peak Detection
help = <0.0..100.0> Black cutoff strength.
url = https://libplacebo.org/options/#black_cutoff001000
name = allow_delayed_peak
file = libplacebo
directory = Video/libplacebo/HDR Peak Detection
help = Allows the peak detection result to be delayed by up to a single frame, which can sometimes improve throughput, at the cost of introducing the possibility of 1-frame flickers on transitions.
default = no
option = yes
option = no
name = color_map
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = Enables the use of these color mapping settings. Disabling this option does not disable color mapping, it just means "use the default options for everything".
default = yes
option = yes
option = no
name = color_map_preset
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = Overrides the value of all options in this section by their default values from the given preset. high_quality also enables HDR contrast recovery.
default = none
option = none
option = default
option = high_quality
name = gamut_mapping
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = Gamut mapping function to use to handle out-of-gamut colors, including colors which are out-of-gamut as a consequence of tone mapping.
default = perceptual
option = clip
option = perceptual
option = softclip
option = relative
option = saturation
option = absolute
option = desaturate
option = darken
option = highlight
option = linear
name = perceptual_deadzone
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = <0.0..1.0> (Relative) chromaticity protection zone for perceptual mapping. Defaults to 0.30.
name = perceptual_strength
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = <0.0..1.0> Strength of the perceptual saturation mapping component. Defaults to 0.80.
name = colorimetric_gamma
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = <0.0..10.0> I vs C curve gamma to use for colorimetric clipping (relative, absolute and darken). Defaults to 1.80.
name = softclip_knee
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = <0.0..1.0> Knee point to use for soft-clipping methods (perceptual, softclip). Defaults to 0.70.
name = softclip_desat
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = <0.0..1.0> Desaturation strength for softclip. Defaults to 0.35.
name = lut3d_size_I
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = <0..1024> Gamut mapping 3DLUT size. Setting a dimension to 0 picks the default value. Defaults to 48.
name = lut3d_size_C
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = <0..1024> Gamut mapping 3DLUT size. Setting a dimension to 0 picks the default value. Defaults to 32.
name = lut3d_size_h
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = <0..1024> Gamut mapping 3DLUT size. Setting a dimension to 0 picks the default value. Defaults to 256.
name = lut3d_tricubic
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = Use higher quality, but slower, tricubic interpolation for gamut mapping 3DLUTs. May substantially improve the 3DLUT gamut mapping accuracy, in particular at smaller 3DLUT sizes. Shouldn't have much effect at the default size.
default = no
option = yes
option = no
name = gamut_expansion
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = If enabled, allows the gamut mapping function to expand the gamut, in cases where the target gamut exceeds that of the source. If disabled, the source gamut will never be enlarged, even when using a gamut mapping function capable of bidirectional mapping.
default = no
option = yes
option = no
name = tone_mapping
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = Tone mapping function to use for adapting between difference luminance ranges, including black point adaptation.
default = spline
option = clip
option = spline
option = st2094-40
option = st2094-10
option = bt2390
option = bt2446a
option = reinhard
option = mobius
option = hable
option = gamma
option = linear
option = linearlight
name = knee_adaptation
file = libplacebo
directory = Video/libplacebo/Color Mapping
url = https://libplacebo.org/options/#tone-mapping-constants
name = knee_minimum
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = <0.0..0.5> Configures the knee point minimum as a percentage of the PQ luminance range. Provides a hard limit on the knee point chosen by knee_adaptation. Defaults to 0.1.
name = knee_maximum
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = <0.5..1.0> Configures the knee point maximum as a percentage of the PQ luminance range. Provides a hard limit on the knee point chosen by knee_adaptation. Defaults to 0.8.
name = knee_default
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = <0.0..1.0> Default knee point to use in the absence of source scene average metadata. Normally, this is ignored in favor of picking the knee point as the (relative) source scene average brightness level. Defaults to 0.4.
name = knee_offset
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = <0.5..2.0> Knee point offset (for bt2390 only). Note that a value of 0.5 is the spec-defined default behavior, which differs from the libplacebo default of 1.0.
name = slope_tuning
file = libplacebo
directory = Video/libplacebo/Color Mapping
url = https://libplacebo.org/options/#tone-mapping-constants
name = slope_offset
file = libplacebo
directory = Video/libplacebo/Color Mapping
url = https://libplacebo.org/options/#tone-mapping-constants
name = spline_contrast
file = libplacebo
directory = Video/libplacebo/Color Mapping
url = https://libplacebo.org/options/#tone-mapping-constants
name = reinhard_contrast
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = <0.0..1.0> For the reinhard function, this specifies the local contrast coefficient at the display peak. Essentially, a value of 0.5 implies that the reference white will be about half as bright as when clipping. Defaults to 0.5.
name = linear_knee
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = <0.0..1.0> For legacy functions (mobius, gamma) which operate on linear light, this directly sets the corresponding knee point. Defaults to 0.3.
name = exposure
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = <0.0..10.0> For linear methods (linear, linearlight), this controls the linear exposure/gain applied to the image. Defaults to 1.0.
name = inverse_tone_mapping
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = If enabled, and supported by the given tone mapping function, will perform inverse tone mapping to expand the dynamic range of a signal. libplacebo is not liable for any HDR-induced eye damage.
default = no
option = yes
option = no
name = tone_map_metadata
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = Data source to use when tone-mapping. Setting this to a specific value allows overriding the default metadata preference logic.
default = any
option = any
option = none
option = hdr10
option = hdr10plus
option = cie_y
name = tone_lut_size
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = <0..4096> Tone mapping LUT size. Setting 0 picks the default size. Defaults to 256.
name = contrast_recovery
file = libplacebo
directory = Video/libplacebo/Color Mapping
url = https://libplacebo.org/options/#contrast_recovery0020
name = contrast_smoothness
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = <1.0..32.0> HDR contrast recovery lowpass kernel size. Increasing or decreasing this will affect the visual appearance substantially. Defaults to 3.5.
name = force_tone_mapping_lut
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = Force the use of a full tone-mapping LUT even for functions that have faster pure GLSL replacements (e.g. clip, linear, saturation). This is a debug option.
default = no
option = yes
option = no
name = visualize_lut
file = libplacebo
directory = Video/libplacebo/Color Mapping
url = https://libplacebo.org/options/#debug-options
default = no
option = yes
option = no
name = visualize_lut_x0
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = Controls where to draw the LUt visualization, relative to the rendered video. Defaults to 0.0.
name = visualize_lut_y0
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = Controls where to draw the LUt visualization, relative to the rendered video. Defaults to 0.0.
name = visualize_lut_x1
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = Controls where to draw the LUt visualization, relative to the rendered video. Defaults to 1.0.
name = visualize_lut_y1
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = Controls where to draw the LUt visualization, relative to the rendered video. Defaults to 1.0.
name = visualize_hue
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = Controls the rotation of the gamut 3DLUT visualization. Rotates the gamut through hue space (around the I axis), in radians. Defaults to 0.0.
name = visualize_theta
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = Controls the rotation of the gamut 3DLUT visualization. The theta parameter vertically rotates the cross section (around the C axis), in radians. Defaults to 0.0.
name = show_clipping
file = libplacebo
directory = Video/libplacebo/Color Mapping
help = Graphically highlight hard-clipped pixels during tone-mapping (i.e. pixels that exceed the claimed source luminance range).
default = no
option = yes
option = no
name = screenshot-directory name = screenshot-directory
file = mpv file = mpv
width = 500 width = 500
type = folder type = folder
directory = Video/Screenshot 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. 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 name = screenshot-format
file = mpv file = mpv
@@ -272,7 +747,7 @@ option = png
name = screenshot-tag-colorspace name = screenshot-tag-colorspace
file = mpv file = mpv
default = no default = yes
directory = Video/Screenshot directory = Video/Screenshot
help = Tag screenshots with the appropriate colorspace. Note that not all formats are supported. help = Tag screenshots with the appropriate colorspace. Note that not all formats are supported.
option = yes option = yes
@@ -333,7 +808,7 @@ name = alang
file = mpv file = mpv
directory = Audio directory = Audio
type = string 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 name = audio-file-auto
file = mpv file = mpv
@@ -349,8 +824,9 @@ name = audio-device
file = mpv file = mpv
directory = Audio directory = Audio
type = string type = string
width = 400
url = https://mpv.io/manual/master/#options-audio-device url = https://mpv.io/manual/master/#options-audio-device
help = <name> Use the given audio device. This consists of the audio output name, e.g. alsa, followed by /, followed by the audio output specific device name. The default value for this option is auto, which tries every audio output in preference order with the default device. help = <name> Use the given audio device. This consists of the audio output name, e.g. alsa, followed by /, followed by the audio output specific device name. The default value for this option is auto, which tries every audio output in preference order with the default device. To list audio devices in mpv.net use the context menu:\nView > More > Show Audio Devices.
name = slang name = slang
file = mpv file = mpv
@@ -398,10 +874,16 @@ type = color
directory = Subtitle 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. 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 name = fullscreen
file = mpv file = mpv
default = no default = no
directory = Screen directory = Window
help = Start the player in fullscreen mode. help = Start the player in fullscreen mode.
option = yes option = yes
option = no option = no
@@ -409,71 +891,92 @@ option = no
name = border name = border
file = mpv file = mpv
default = yes default = yes
directory = Screen directory = Window
help = Show window with decoration (titlebar, border). help = Show window with decoration (titlebar, border).
option = yes option = yes
option = no option = no
name = title-bar
file = mpv
default = yes
directory = Window
help = Set this to no in order to hide the window title bar.
option = yes
option = no
name = screen name = screen
file = mpv 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. 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 name = osd-playing-msg
file = mpv file = mpv
width = 300 width = 300
directory = Screen directory = Window
type = string 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: 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 url = https://mpv.io/manual/master/#property-expansion
name = osd-font-size name = osd-font-size
file = mpv file = mpv
directory = Screen directory = Window
help = Specify the OSD font size. See sub-font-size for details. Default: 55 help = Specify the OSD font size. See sub-font-size for details. Default: 55
name = osd-duration name = osd-duration
file = mpv file = mpv
directory = Screen directory = Window
help = Set the duration of the OSD messages in ms. Default: 1000 help = Set the duration of the OSD messages in ms. Default: 1000
name = osd-scale-by-window name = osd-scale-by-window
file = mpv file = mpv
default = yes 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. 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 = yes
option = no option = no
name = autofit name = autofit
file = mpv file = mpv
directory = Screen directory = Window
help = <int> Initial window height in percent. Default: 60 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 name = autofit-smaller
file = mpv file = mpv
directory = Screen directory = Window
help = <int> Minimum window height in percent. Default: 10 help = <int> Minimum window height in percent. Default: 10
name = autofit-larger name = autofit-larger
file = mpv file = mpv
directory = Screen directory = Window
help = <int> Maximum window height in percent. Default: 80 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 name = start-size
file = mpvnet file = mpvnet
default = height-session default = height-session
directory = Screen directory = Window
help = Setting to remember the window size. (mpv.net option) help = Setting to remember the window size. (mpv.net option)
option = width-session Window width is remembered in the current session option = width-session Window width is remembered in the current session
option = width-always Window width is always remembered option = width-always Window width is always remembered
@@ -486,25 +989,25 @@ option = always Window size is always remembered
name = keepaspect-window name = keepaspect-window
file = mpv file = mpv
default = yes default = yes
directory = Screen directory = Window
help = keepaspect-window will lock the window size to the video aspect. Default: yes help = keepaspect-window will lock the window size to the video aspect. Default: yes
option = yes option = yes
option = no option = no
name = minimum-aspect-ratio name = minimum-aspect-ratio
file = mpvnet 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) 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 name = minimum-aspect-ratio-audio
file = mpvnet file = mpvnet
directory = Screen directory = Window
help = Same as minimum-aspect-ratio but used for audio files. help = Same as minimum-aspect-ratio but used for audio files.
name = remember-window-position name = remember-window-position
file = mpvnet file = mpvnet
default = no default = no
directory = Screen directory = Window
help = Save the window position on exit. (mpv.net option) help = Save the window position on exit. (mpv.net option)
option = yes option = yes
option = no option = no
@@ -512,7 +1015,7 @@ option = no
name = snap-window name = snap-window
file = mpv file = mpv
default = no default = no
directory = Screen directory = Window
help = Snap the player window to screen edges. help = Snap the player window to screen edges.
option = yes option = yes
option = no option = no
@@ -520,27 +1023,8 @@ option = no
name = window-maximized name = window-maximized
file = mpv file = mpv
default = no default = no
directory = Screen
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 = title
file = mpv
directory = Window directory = Window
width = 400 help = Start with a maximized window.
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 = taskbar-progress
file = mpv
default = yes
directory = Playback
help = Show progress in taskbar.
option = yes option = yes
option = no option = no
@@ -644,9 +1128,8 @@ url = https://mpv.io/manual/master/#options-input-ipc-server
name = language name = language
file = mpvnet file = mpvnet
default = system default = system
directory = UI directory = Appearance
help = User interface display language.\nmpv.net must be restarted after a change.\nInterested joining our translation team?: help = User interface display language.\nmpv.net must be restarted after a change.
url = https://app.transifex.com/stax76/teams/
option = system option = system
option = english option = english
option = chinese-china option = chinese-china
@@ -655,7 +1138,7 @@ option = german
name = dark-mode name = dark-mode
file = mpvnet file = mpvnet
default = always default = always
directory = UI directory = Appearance
help = Changes between a light and dark theme.\nmpv.net must be restarted after a change.\nmpv.net specific option. help = Changes between a light and dark theme.\nmpv.net must be restarted after a change.\nmpv.net specific option.
option = always option = always
option = system Available on Windows 10 or higher option = system Available on Windows 10 or higher
@@ -663,13 +1146,13 @@ option = never
name = dark-theme name = dark-theme
file = mpvnet file = mpvnet
directory = UI directory = Appearance
url = https://github.com/mpvnet-player/mpv.net/blob/main/docs/manual.md#color-theme url = https://github.com/mpvnet-player/mpv.net/blob/main/docs/manual.md#color-theme
help = Color theme used in dark mode.\nmpv.net must be restarted after a change.\nmpv.net specific option. Default: dark help = Color theme used in dark mode.\nmpv.net must be restarted after a change.\nmpv.net specific option. Default: dark
name = light-theme name = light-theme
file = mpvnet file = mpvnet
directory = UI directory = Appearance
url = https://github.com/mpvnet-player/mpv.net/blob/main/docs/manual.md#color-theme 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 help = Color theme used in light mode.\nmpv.net must be restarted after a change.\nmpv.net specific option. Default: light

View File

@@ -16,6 +16,7 @@ public abstract class Setting
public string? Value { get; set; } public string? Value { get; set; }
public int Width { get; set; } public int Width { get; set; }
public int OptionNameWidth { get; set; } = 100;
public ConfItem? ConfItem { get; set; } public ConfItem? ConfItem { get; set; }
} }
@@ -35,12 +36,13 @@ public class OptionSettingOption
public string? Name { get; set; } public string? Name { get; set; }
public string? Help { get; set; } public string? Help { get; set; }
public int OptionWidth { get => OptionSetting!.OptionNameWidth; }
public OptionSetting? OptionSetting { get; set; } public OptionSetting? OptionSetting { get; set; }
public string? Text public string? Text
{ {
get => string.IsNullOrEmpty(_text) ? Name : _text; get => _text ?? Name;
set => _text = value; set => _text = value;
} }

View 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");
}
}

View File

@@ -28,8 +28,8 @@
<KeyBinding Key="n" Modifiers="Ctrl" Command="{Binding ShowMpvNetSpecificSettingsCommand}"/> <KeyBinding Key="n" Modifiers="Ctrl" Command="{Binding ShowMpvNetSpecificSettingsCommand}"/>
<KeyBinding Key="F5" Command="{Binding PreviewMpvConfFileCommand}"/> <KeyBinding Key="F5" Command="{Binding PreviewMpvConfFileCommand}"/>
<KeyBinding Key="F6" Command="{Binding PreviewMpvNetConfFileCommand}"/> <KeyBinding Key="F6" Command="{Binding PreviewMpvNetConfFileCommand}"/>
<KeyBinding Key="F1" Command="{Binding ShowMpvManualCommand}"/> <KeyBinding Key="F1" Modifiers="Ctrl" Command="{Binding ShowMpvManualCommand}"/>
<KeyBinding Key="F2" Command="{Binding ShowMpvNetManualCommand}"/> <KeyBinding Key="F2" Modifiers="Ctrl" Command="{Binding ShowMpvNetManualCommand}"/>
</Window.InputBindings> </Window.InputBindings>
<Grid> <Grid>
@@ -40,7 +40,7 @@
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="170" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
@@ -48,6 +48,7 @@
x:Name="SearchControl" x:Name="SearchControl"
HintText="Find a setting (Ctrl+F)" HintText="Find a setting (Ctrl+F)"
Margin="20,20,0,10" Margin="20,20,0,10"
MaxWidth="190"
Text="{Binding SearchText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Text="{Binding SearchText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
/> />
@@ -135,12 +136,12 @@
<Separator /> <Separator />
<MenuItem <MenuItem
Header="Show mpv manual" Header="Show mpv manual"
InputGestureText="F1" InputGestureText="Ctrl+F1"
Command="{Binding Data.ShowMpvManualCommand, Source={StaticResource BindingProxy}}" Command="{Binding Data.ShowMpvManualCommand, Source={StaticResource BindingProxy}}"
/> />
<MenuItem <MenuItem
Header="Show mpv.net manual" Header="Show mpv.net manual"
InputGestureText="F2" InputGestureText="Ctrl+F2"
Command="{Binding Data.ShowMpvNetManualCommand, Source={StaticResource BindingProxy}}" Command="{Binding Data.ShowMpvNetManualCommand, Source={StaticResource BindingProxy}}"
/> />
</ContextMenu> </ContextMenu>

View File

@@ -20,13 +20,16 @@ namespace MpvNet.Windows.WPF;
public partial class ConfWindow : Window, INotifyPropertyChanged public partial class ConfWindow : Window, INotifyPropertyChanged
{ {
List<Setting> Settings = Conf.LoadConf(Properties.Resources.editor_conf.TrimEnd()); List<Setting> _settings = Conf.LoadConf(Properties.Resources.editor_conf.TrimEnd());
List<ConfItem> ConfItems = new List<ConfItem>(); List<ConfItem> _confItems = new List<ConfItem>();
public ObservableCollection<string> FilterStrings { get; } = new(); string _initialContent;
string InitialContent; string _themeConf = GetThemeConf();
string ThemeConf = GetThemeConf();
string? _searchText; string? _searchText;
List<NodeViewModel>? _nodes; List<NodeViewModel>? _nodes;
bool _shown;
int _useSpace;
int _useNoSpace;
public event PropertyChangedEventHandler? PropertyChanged; public event PropertyChangedEventHandler? PropertyChanged;
public ConfWindow() public ConfWindow()
@@ -37,7 +40,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
LoadConf(App.ConfPath); LoadConf(App.ConfPath);
LoadLibplaceboConf(); LoadLibplaceboConf();
LoadSettings(); LoadSettings();
InitialContent = GetCompareString(); _initialContent = GetCompareString();
if (string.IsNullOrEmpty(App.Settings.ConfigEditorSearch)) if (string.IsNullOrEmpty(App.Settings.ConfigEditorSearch))
SearchText = "General:"; SearchText = "General:";
@@ -48,9 +51,11 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
SelectNodeFromSearchText(node); SelectNodeFromSearchText(node);
foreach (var node in Nodes) foreach (var node in Nodes)
ExpandNode(node); node.IsExpanded = true;
} }
public ObservableCollection<string> FilterStrings { get; } = new();
public Theme? Theme => Theme.Current; public Theme? Theme => Theme.Current;
public string SearchText public string SearchText
@@ -72,7 +77,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
{ {
var rootNode = new TreeNode(); var rootNode = new TreeNode();
foreach (Setting setting in Settings) foreach (Setting setting in _settings)
AddNode(rootNode.Children, setting.Directory!); AddNode(rootNode.Children, setting.Directory!);
_nodes = new NodeViewModel(rootNode).Children; _nodes = new NodeViewModel(rootNode).Children;
@@ -125,16 +130,18 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
void LoadSettings() void LoadSettings()
{ {
foreach (Setting setting in Settings) foreach (Setting setting in _settings)
{ {
setting.StartValue = setting.Value; setting.StartValue = setting.Value;
if (!FilterStrings.Contains(setting.Directory!)) if (!FilterStrings.Contains(setting.Directory!))
FilterStrings.Add(setting.Directory!); FilterStrings.Add(setting.Directory!);
foreach (ConfItem item in ConfItems) foreach (ConfItem item in _confItems)
{ {
if (setting.Name == item.Name && item.Section == "" && !item.IsSectionItem) if (setting.Name == item.Name &&
setting.File == item.File &&
item.Section == "" && !item.IsSectionItem)
{ {
setting.Value = item.Value; setting.Value = item.Value;
setting.StartValue = setting.Value; setting.StartValue = setting.Value;
@@ -149,6 +156,9 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
MainStackPanel.Children.Add(new StringSettingControl(s) { Visibility = Visibility.Collapsed }); MainStackPanel.Children.Add(new StringSettingControl(s) { Visibility = Visibility.Collapsed });
break; break;
case OptionSetting s: 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 }); MainStackPanel.Children.Add(new OptionSettingControl(s) { Visibility = Visibility.Collapsed });
break; break;
} }
@@ -157,65 +167,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
static string GetThemeConf() => Theme.DarkMode + App.DarkTheme + App.LightTheme; static string GetThemeConf() => Theme.DarkMode + App.DarkTheme + App.LightTheme;
protected override void OnClosed(EventArgs e) string GetCompareString() => string.Join("", _settings.Select(item => item.Name + item.Value).ToArray());
{
base.OnClosed(e);
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"));
foreach (Setting it in Settings)
{
if (it.Value != it.StartValue)
{
if (it.File == "mpv")
{
Player.ProcessProperty(it.Name, it.Value);
Player.SetPropertyString(it.Name!, it.Value!);
}
else if (it.File == "mpvnet")
App.ProcessProperty(it.Name ?? "", it.Value ?? "", true);
}
}
Theme.Init();
Theme.UpdateWpfColors();
if (ThemeConf != GetThemeConf())
MessageBox.Show("Changed theme settings require mpv.net being restarted.", "Info");
}
bool _shown;
protected override void OnContentRendered(EventArgs e)
{
base.OnContentRendered(e);
if (_shown)
return;
_shown = true;
Application.Current.Dispatcher.BeginInvoke(() => {
SearchControl.SearchTextBox.SelectAll();
},
DispatcherPriority.Background);
}
string GetCompareString() => string.Join("", Settings.Select(item => item.Name + item.Value).ToArray());
void LoadConf(string file) void LoadConf(string file)
{ {
@@ -227,9 +179,12 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
bool isSectionItem = false; bool isSectionItem = false;
foreach (string currentLine in File.ReadAllLines(file)) foreach (string it in File.ReadAllLines(file))
{ {
string line = currentLine.Trim(); string line = it.Trim();
if (line.StartsWith("-"))
line = line.TrimStart('-');
if (line == "") if (line == "")
comment += "\r\n"; comment += "\r\n";
@@ -238,8 +193,8 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
else if (line.StartsWith("[") && line.Contains(']')) else if (line.StartsWith("[") && line.Contains(']'))
{ {
if (!isSectionItem && comment != "" && comment != "\r\n") if (!isSectionItem && comment != "" && comment != "\r\n")
ConfItems.Add(new ConfItem() { _confItems.Add(new ConfItem() {
Comment = comment, File = System.IO.Path.GetFileNameWithoutExtension(file)}); Comment = comment, File = Path.GetFileNameWithoutExtension(file)});
section = line.Substring(0, line.IndexOf("]") + 1); section = line.Substring(0, line.IndexOf("]") + 1);
comment = ""; comment = "";
@@ -248,17 +203,30 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
else if (line.Contains('=') || Regex.Match(line, "^[\\w-]+$").Success) else if (line.Contains('=') || Regex.Match(line, "^[\\w-]+$").Success)
{ {
if (!line.Contains('=')) if (!line.Contains('='))
{
if (line.StartsWith("no-"))
{
line = line.Substring(3);
line += "=no";
}
else
line += "=yes"; line += "=yes";
}
if (line.Contains(" =") || line.Contains("= "))
_useSpace += 1;
else
_useNoSpace += 1;
ConfItem item = new(); ConfItem item = new();
item.File = System.IO.Path.GetFileNameWithoutExtension(file); item.File = Path.GetFileNameWithoutExtension(file);
item.IsSectionItem = isSectionItem; item.IsSectionItem = isSectionItem;
item.Comment = comment; item.Comment = comment;
comment = ""; comment = "";
item.Section = section; item.Section = section;
section = ""; section = "";
if (line.Contains('#') && !line.Contains("'") && !line.Contains("\"")) if (line.Contains('#') && !line.Contains('\'') && !line.Contains('"'))
{ {
item.LineComment = line.Substring(line.IndexOf("#")).Trim(); item.LineComment = line.Substring(line.IndexOf("#")).Trim();
line = line.Substring(0, line.IndexOf("#")).Trim(); line = line.Substring(0, line.IndexOf("#")).Trim();
@@ -282,7 +250,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
item.Name = left; item.Name = left;
item.Value = right; item.Value = right;
ConfItems.Add(item); _confItems.Add(item);
} }
} }
} }
@@ -291,7 +259,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
{ {
List<string> pairs = new(); List<string> pairs = new();
foreach (Setting setting in Settings) foreach (Setting setting in _settings)
{ {
if (filename != setting.File) if (filename != setting.File)
continue; continue;
@@ -305,7 +273,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
void LoadLibplaceboConf() void LoadLibplaceboConf()
{ {
foreach (ConfItem item in ConfItems.ToArray()) foreach (ConfItem item in _confItems.ToArray())
if (item.Name == "libplacebo-opts") if (item.Name == "libplacebo-opts")
LoadKeyValueList(item.Value, "libplacebo"); LoadKeyValueList(item.Value, "libplacebo");
} }
@@ -327,7 +295,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
item.Name = left; item.Name = left;
item.Value = right; item.Value = right;
item.File = file; item.File = file;
ConfItems.Add(item); _confItems.Add(item);
} }
} }
@@ -352,8 +320,9 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
List<string> namesWritten = new List<string>(); List<string> namesWritten = new List<string>();
string equalString = _useSpace > _useNoSpace ? " = " : "=";
foreach (ConfItem item in ConfItems) foreach (ConfItem item in _confItems)
{ {
if (filename != item.File || item.Section != "" || item.IsSectionItem) if (filename != item.File || item.Section != "" || item.IsSectionItem)
continue; continue;
@@ -365,7 +334,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
{ {
if (item.Name != "") if (item.Name != "")
{ {
sb.Append(item.Name + " = " + EscapeValue(item.Value)); sb.Append(item.Name + equalString + EscapeValue(item.Value));
if (item.LineComment != "") if (item.LineComment != "")
sb.Append(" " + item.LineComment); sb.Append(" " + item.LineComment);
@@ -376,7 +345,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
} }
else if ((item.SettingBase.Value ?? "") != item.SettingBase.Default) else if ((item.SettingBase.Value ?? "") != item.SettingBase.Default)
{ {
sb.Append(item.Name + " = " + EscapeValue(item.SettingBase.Value!)); sb.Append(item.Name + equalString + EscapeValue(item.SettingBase.Value!));
if (item.LineComment != "") if (item.LineComment != "")
sb.Append(" " + item.LineComment); sb.Append(" " + item.LineComment);
@@ -386,16 +355,16 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
} }
} }
foreach (Setting setting in Settings) foreach (Setting setting in _settings)
{ {
if (filename != setting.File || namesWritten.Contains(setting.Name!)) if (filename != setting.File || namesWritten.Contains(setting.Name!))
continue; continue;
if ((setting.Value ?? "") != setting.Default) if ((setting.Value ?? "") != setting.Default)
sb.AppendLine(setting.Name + " = " + EscapeValue(setting.Value!)); sb.AppendLine(setting.Name + equalString + EscapeValue(setting.Value!));
} }
foreach (ConfItem item in ConfItems) foreach (ConfItem item in _confItems)
{ {
if (filename != item.File || (item.Section == "" && !item.IsSectionItem)) if (filename != item.File || (item.Section == "" && !item.IsSectionItem))
continue; continue;
@@ -411,7 +380,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
if (item.Comment != "") if (item.Comment != "")
sb.Append(item.Comment); sb.Append(item.Comment);
sb.Append(item.Name + " = " + EscapeValue(item.Value)); sb.Append(item.Name + equalString + EscapeValue(item.Value));
if (item.LineComment != "") if (item.LineComment != "")
sb.Append(" " + item.LineComment); sb.Append(" " + item.LineComment);
@@ -461,6 +430,47 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
i.Update(); i.Update();
} }
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
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"));
foreach (Setting it in _settings)
{
if (it.Value != it.StartValue)
{
if (it.File == "mpv")
{
Player.ProcessProperty(it.Name, it.Value);
Player.SetPropertyString(it.Name!, it.Value!);
}
else if (it.File == "mpvnet")
App.ProcessProperty(it.Name ?? "", it.Value ?? "", true);
}
}
Theme.Init();
Theme.UpdateWpfColors();
if (_themeConf != GetThemeConf())
MessageBox.Show("Changed theme settings require mpv.net being restarted.", "Info");
}
protected override void OnKeyDown(KeyEventArgs e) protected override void OnKeyDown(KeyEventArgs e)
{ {
base.OnKeyDown(e); base.OnKeyDown(e);
@@ -475,9 +485,22 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
} }
} }
protected void OnPropertyChanged([CallerMemberName] string? name = null) protected void OnPropertyChanged([CallerMemberName] string? name = null) =>
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
protected override void OnContentRendered(EventArgs e)
{
base.OnContentRendered(e);
if (_shown)
return;
_shown = true;
Application.Current.Dispatcher.BeginInvoke(() => {
SearchControl.SearchTextBox.SelectAll();
},
DispatcherPriority.Background);
} }
void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e) void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
@@ -498,6 +521,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
if (node.Path + ":" == SearchText) if (node.Path + ":" == SearchText)
{ {
node.IsSelected = true; node.IsSelected = true;
node.IsExpanded = true;
return; return;
} }
@@ -514,14 +538,6 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
UnselectNode(it); UnselectNode(it);
} }
void ExpandNode(NodeViewModel node)
{
node.IsExpanded = true;
foreach (var it in node.Children)
ExpandNode(it);
}
[RelayCommand] void ShowMpvNetSpecificSettings() => SearchText = "mpv.net"; [RelayCommand] void ShowMpvNetSpecificSettings() => SearchText = "mpv.net";
[RelayCommand] void PreviewMpvConfFile() => Msg.ShowInfo(GetContent("mpv")); [RelayCommand] void PreviewMpvConfFile() => Msg.ShowInfo(GetContent("mpv"));

View 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>

View File

@@ -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;
}
}

View File

@@ -92,7 +92,6 @@ public partial class CommandPaletteControl : UserControl
if (item.Binding != null) if (item.Binding != null)
{ {
// TODO: CommandItem.Alias
//if (item.CommandItem.Alias.ContainsEx(filter)) //if (item.CommandItem.Alias.ContainsEx(filter))
// return true; // return true;

View File

@@ -66,8 +66,14 @@
Background="{Binding Theme.Background}" Background="{Binding Theme.Background}"
/> />
<TextBlock x:Name="LinkTextBlock" Margin="0,10"> <TextBlock
<local:HyperlinkEx x:Name="Link"></local:HyperlinkEx> x:Name="LinkTextBlock"
Margin="2,0,0,0"
>
<local:HyperlinkEx
x:Name="Link"
Foreground="{Binding Theme.Heading}"
/>
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
</Grid> </Grid>

View File

@@ -21,6 +21,10 @@ public partial class OptionSettingControl : UserControl, ISettingControl
HelpTextBox.Visibility = Visibility.Collapsed; HelpTextBox.Visibility = Visibility.Collapsed;
HelpTextBox.Text = optionSetting.Help; HelpTextBox.Text = optionSetting.Help;
if (string.IsNullOrEmpty(optionSetting.Help))
LinkTextBlock.Margin = new Thickness(2, 6, 0, 0);
ItemsControl.ItemsSource = optionSetting.Options; ItemsControl.ItemsSource = optionSetting.Options;
if (string.IsNullOrEmpty(optionSetting.URL)) if (string.IsNullOrEmpty(optionSetting.URL))

View File

@@ -24,7 +24,7 @@
Name="SearchTextBox" Name="SearchTextBox"
Height="25" Height="25"
BorderThickness="2" BorderThickness="2"
Padding="2" Padding="2,2,20,2"
Background="Transparent" Background="Transparent"
Foreground="{Binding Theme.Foreground}" Foreground="{Binding Theme.Foreground}"
CaretBrush="{Binding Theme.Foreground}" CaretBrush="{Binding Theme.Foreground}"

View File

@@ -39,11 +39,17 @@ public partial class SearchControl : UserControl
{ {
HintTextBlock.Text = string.IsNullOrEmpty(Text) ? HintText : ""; HintTextBlock.Text = string.IsNullOrEmpty(Text) ? HintText : "";
if (string.IsNullOrEmpty(Text) || HideClearButton || Text.Length > 21) if (string.IsNullOrEmpty(Text) || HideClearButton || Text.Length > 30)
{
SearchTextBox.Padding = new Thickness(2);
SearchClearButton.Visibility = Visibility.Hidden; SearchClearButton.Visibility = Visibility.Hidden;
}
else else
{
SearchTextBox.Padding = new Thickness(2, 2, 20, 2);
SearchClearButton.Visibility = Visibility.Visible; SearchClearButton.Visibility = Visibility.Visible;
} }
}
public string Text public string Text
{ {

View File

@@ -60,8 +60,14 @@
Background="{Binding Theme.Background}" Background="{Binding Theme.Background}"
/> />
<TextBlock x:Name="LinkTextBlock" Margin="0,10"> <TextBlock
<local:HyperlinkEx x:Name="Link"></local:HyperlinkEx> x:Name="LinkTextBlock"
Margin="2,0"
>
<local:HyperlinkEx
x:Name="Link"
Foreground="{Binding Theme.Heading}"
/>
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
</Grid> </Grid>

View File

@@ -33,6 +33,9 @@ public partial class StringSettingControl : UserControl, ISettingControl
if (string.IsNullOrEmpty(stringSetting.URL)) if (string.IsNullOrEmpty(stringSetting.URL))
LinkTextBlock.Visibility = Visibility.Collapsed; LinkTextBlock.Visibility = Visibility.Collapsed;
if (string.IsNullOrEmpty(stringSetting.Help))
HelpTextBox.Visibility = Visibility.Collapsed;
} }
public Theme? Theme => Theme.Current; public Theme? Theme => Theme.Current;

View File

@@ -5,7 +5,7 @@ using System.Windows;
namespace HandyControl.Tools.Interop namespace HandyControl.Tools.Interop
{ {
internal class InteropValues public class InteropValues
{ {
internal static class ExternDll internal static class ExternDll
{ {
@@ -290,7 +290,7 @@ namespace HandyControl.Tools.Interop
} }
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
internal class WINDOWPOS public class WINDOWPOS
{ {
public IntPtr hwnd; public IntPtr hwnd;
public IntPtr hwndInsertAfter; public IntPtr hwndInsertAfter;

View File

@@ -6,6 +6,183 @@
xmlns:local="clr-namespace:MpvNet.Windows.WPF" 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 TargetType="local:HyperlinkEx">
<Style.Triggers> <Style.Triggers>
<Trigger Property="IsMouseOver" Value="True"> <Trigger Property="IsMouseOver" Value="True">
@@ -53,17 +230,20 @@
</Style> </Style>
<Style TargetType="TextBox"> <Style TargetType="TextBox">
<Setter Property="MinHeight" Value="25" />
<Setter Property="Template"> <Setter Property="Template">
<Setter.Value> <Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}"> <ControlTemplate TargetType="{x:Type TextBox}">
<Border x:Name="border" <Border
x:Name="border"
BorderBrush="{DynamicResource PrimaryTextBrush}" BorderBrush="{DynamicResource PrimaryTextBrush}"
BorderThickness="{TemplateBinding BorderThickness}" BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}" Background="{TemplateBinding Background}"
CornerRadius="3" CornerRadius="3"
SnapsToDevicePixels="True"> SnapsToDevicePixels="True">
<ScrollViewer x:Name="PART_ContentHost" <ScrollViewer
x:Name="PART_ContentHost"
Focusable="false" Focusable="false"
HorizontalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"/> VerticalScrollBarVisibility="Hidden"/>

View File

@@ -7,6 +7,8 @@ namespace MpvNet.Windows.WPF;
public class WpfTranslator : ITranslator public class WpfTranslator : ITranslator
{ {
string _localizerLangauge = "";
static Language[] Languages { get; } = new Language[] { static Language[] Languages { get; } = new Language[] {
new("english", "en", "en"), new("english", "en", "en"),
new("chinese-china", "zh-CN", "zh"), // Chinese (Simplified) new("chinese-china", "zh-CN", "zh"), // Chinese (Simplified)
@@ -21,8 +23,11 @@ public class WpfTranslator : ITranslator
void InitNGettextWpf() void InitNGettextWpf()
{ {
if (Translation.Localizer == null) if (Translation.Localizer == null || _localizerLangauge != App.Language)
{
CompositionRoot.Compose("mpvnet", GetCulture(App.Language), Folder.Startup + "Locale"); CompositionRoot.Compose("mpvnet", GetCulture(App.Language), Folder.Startup + "Locale");
_localizerLangauge = App.Language;
}
} }
string GetSystemLanguage() string GetSystemLanguage()

View File

@@ -6,6 +6,7 @@ using System.Threading;
using System.Windows.Forms; using System.Windows.Forms;
using System.Windows.Threading; using System.Windows.Threading;
using System.Windows.Forms.Integration; using System.Windows.Forms.Integration;
using System.Text.RegularExpressions;
using MpvNet.Windows.WPF; using MpvNet.Windows.WPF;
using MpvNet.Windows.UI; using MpvNet.Windows.UI;
@@ -13,12 +14,13 @@ using MpvNet.Help;
using MpvNet.ExtensionMethod; using MpvNet.ExtensionMethod;
using MpvNet.MVVM; using MpvNet.MVVM;
using MpvNet.Windows.WPF.MsgBox; using MpvNet.Windows.WPF.MsgBox;
using MpvNet.Windows.Help;
using WpfControls = System.Windows.Controls; using WpfControls = System.Windows.Controls;
using CommunityToolkit.Mvvm.Messaging; using CommunityToolkit.Mvvm.Messaging;
using static MpvNet.Windows.Native.WinApi; using static MpvNet.Windows.Native.WinApi;
using MpvNet.Windows.Help; using static MpvNet.Windows.Help.WinApiHelp;
namespace MpvNet.Windows.WinForms; namespace MpvNet.Windows.WinForms;
@@ -42,13 +44,13 @@ public partial class MainForm : Form
bool _contextMenuIsReady; bool _contextMenuIsReady;
bool _wasMaximized; bool _wasMaximized;
bool _maxSizeSet;
public MainForm() public MainForm()
{ {
InitializeComponent(); InitializeComponent();
if (Environment.OSVersion.Version >= new Version(10, 0, 18985) && Theme.DarkMode) UpdateDarkMode();
DwmSetWindowAttribute(Handle, 20, new[] { 1 }, 4); // DWMWA_USE_IMMERSIVE_DARK_MODE = 20
try try
{ {
@@ -67,7 +69,6 @@ public partial class MainForm : Form
GuiCommand.Current.WindowScaleNet += GuiCommand_WindowScaleNet; GuiCommand.Current.WindowScaleNet += GuiCommand_WindowScaleNet;
GuiCommand.Current.ShowMenu += GuiCommand_ShowMenu; GuiCommand.Current.ShowMenu += GuiCommand_ShowMenu;
if (Player.GPUAPI != "vulkan")
Init(); Init();
_taskbarButtonCreatedMessage = RegisterWindowMessage("TaskbarButtonCreated"); _taskbarButtonCreatedMessage = RegisterWindowMessage("TaskbarButtonCreated");
@@ -125,6 +126,12 @@ public partial class MainForm : Form
} }
} }
void UpdateDarkMode()
{
if (Environment.OSVersion.Version >= new Version(10, 0, 18985))
DwmSetWindowAttribute(Handle, 20, new[] { Theme.DarkMode ? 1 : 0 }, 4); // DWMWA_USE_IMMERSIVE_DARK_MODE = 20
}
void Player_ClientMessage(string[] args) void Player_ClientMessage(string[] args)
{ {
if (Command.Current.Commands.ContainsKey(args[0])) if (Command.Current.Commands.ContainsKey(args[0]))
@@ -151,6 +158,7 @@ public partial class MainForm : Form
Player.ObservePropertyBool("fullscreen", PropChangeFullscreen); Player.ObservePropertyBool("fullscreen", PropChangeFullscreen);
Player.ObservePropertyBool("keepaspect-window", value => Player.KeepaspectWindow = value); Player.ObservePropertyBool("keepaspect-window", value => Player.KeepaspectWindow = value);
Player.ObservePropertyBool("ontop", PropChangeOnTop); Player.ObservePropertyBool("ontop", PropChangeOnTop);
Player.ObservePropertyBool("title-bar", PropChangeTitleBar);
Player.ObservePropertyString("sid", PropChangeSid); Player.ObservePropertyString("sid", PropChangeSid);
Player.ObservePropertyString("aid", PropChangeAid); Player.ObservePropertyString("aid", PropChangeAid);
@@ -162,6 +170,7 @@ public partial class MainForm : Form
Player.ObservePropertyDouble("window-scale", PropChangeWindowScale); Player.ObservePropertyDouble("window-scale", PropChangeWindowScale);
Player.ProcessCommandLineArgsPost();
Player.ProcessCommandLineFiles(); Player.ProcessCommandLineFiles();
} }
@@ -173,7 +182,7 @@ public partial class MainForm : Form
BeginInvoke(() => { BeginInvoke(() => {
SetSize( SetSize(
(int)(Player.VideoSize.Width * scale), (int)(Player.VideoSize.Width * scale),
(int)Math.Ceiling(Player.VideoSize.Height * scale), (int)Math.Floor(Player.VideoSize.Height * scale),
Screen.FromControl(this), false); Screen.FromControl(this), false);
}); });
} }
@@ -199,7 +208,7 @@ public partial class MainForm : Form
else else
{ {
w = (int)(ClientSize.Width * scale); w = (int)(ClientSize.Width * scale);
h = (int)Math.Ceiling(w * Player.VideoSize.Height / (double)Player.VideoSize.Width); h = (int)Math.Floor(w * Player.VideoSize.Height / (double)Player.VideoSize.Width);
} }
SetSize(w, h, Screen.FromControl(this), false); SetSize(w, h, Screen.FromControl(this), false);
@@ -210,7 +219,7 @@ public partial class MainForm : Form
{ {
BeginInvoke(() => { BeginInvoke(() => {
Screen screen = Screen.FromControl(this); Screen screen = Screen.FromControl(this);
Rectangle workingArea = WinApiHelp.GetWorkingArea(Handle, screen.WorkingArea); Rectangle workingArea = GetWorkingArea(Handle, screen.WorkingArea);
switch (direction) switch (direction)
{ {
@@ -239,7 +248,7 @@ public partial class MainForm : Form
BeginInvoke(() => { BeginInvoke(() => {
SetSize( SetSize(
(int)(Player.VideoSize.Width * scale), (int)(Player.VideoSize.Width * scale),
(int)Math.Ceiling(Player.VideoSize.Height * scale), (int)Math.Floor(Player.VideoSize.Height * scale),
Screen.FromControl(this), false); Screen.FromControl(this), false);
Player.Command($"show-text \"window-scale {scale.ToString(CultureInfo.InvariantCulture)}\""); Player.Command($"show-text \"window-scale {scale.ToString(CultureInfo.InvariantCulture)}\"");
}); });
@@ -506,7 +515,7 @@ public partial class MainForm : Form
return null; return null;
} }
void SetFormPosAndSize(bool force = false, bool checkAutofit = true) void SetFormPosAndSize(bool force = false, bool checkAutofit = true, bool load = false)
{ {
if (!force) if (!force)
{ {
@@ -521,7 +530,7 @@ public partial class MainForm : Form
} }
Screen screen = Screen.FromControl(this); Screen screen = Screen.FromControl(this);
Rectangle workingArea = WinApiHelp.GetWorkingArea(Handle, screen.WorkingArea); Rectangle workingArea = GetWorkingArea(Handle, screen.WorkingArea);
int autoFitHeight = Convert.ToInt32(workingArea.Height * Player.Autofit); int autoFitHeight = Convert.ToInt32(workingArea.Height * Player.Autofit);
if (App.AutofitAudio > 1) if (App.AutofitAudio > 1)
@@ -564,12 +573,12 @@ public partial class MainForm : Form
else if (App.StartSize == "height-always" || App.StartSize == "height-session") else if (App.StartSize == "height-always" || App.StartSize == "height-session")
{ {
height = ClientSize.Height; height = ClientSize.Height;
width = height * videoSize.Width / videoSize.Height; width = (int)Math.Ceiling(height * videoSize.Width / (double)videoSize.Height);
} }
else if (App.StartSize == "width-always" || App.StartSize == "width-session") else if (App.StartSize == "width-always" || App.StartSize == "width-session")
{ {
width = ClientSize.Width; width = ClientSize.Width;
height = (int)Math.Ceiling(width * videoSize.Height / (double)videoSize.Width); height = (int)Math.Floor(width * videoSize.Height / (double)videoSize.Width);
} }
} }
else else
@@ -579,22 +588,22 @@ public partial class MainForm : Form
if (App.StartSize == "height-always" && windowSize.Height != 0) if (App.StartSize == "height-always" && windowSize.Height != 0)
{ {
height = windowSize.Height; height = windowSize.Height;
width = height * videoSize.Width / videoSize.Height; width = (int)Math.Ceiling(height * videoSize.Width / (double)videoSize.Height);
} }
else if (App.StartSize == "height-session" || App.StartSize == "session") else if (App.StartSize == "height-session" || App.StartSize == "session")
{ {
height = autoFitHeight; height = autoFitHeight;
width = height * videoSize.Width / videoSize.Height; width = (int)Math.Ceiling(height * videoSize.Width / (double)videoSize.Height);
} }
else if(App.StartSize == "width-always" && windowSize.Height != 0) else if(App.StartSize == "width-always" && windowSize.Height != 0)
{ {
width = windowSize.Width; width = windowSize.Width;
height = (int)Math.Ceiling(width * videoSize.Height / (double)videoSize.Width); height = (int)Math.Floor(width * videoSize.Height / (double)videoSize.Width);
} }
else if (App.StartSize == "width-session") else if (App.StartSize == "width-session")
{ {
width = autoFitHeight / 9 * 16; width = autoFitHeight / 9 * 16;
height = (int)Math.Ceiling(width * videoSize.Height / (double)videoSize.Width); height = (int)Math.Floor(width * videoSize.Height / (double)videoSize.Width);
} }
else if (App.StartSize == "always" && windowSize.Height != 0) else if (App.StartSize == "always" && windowSize.Height != 0)
{ {
@@ -605,12 +614,12 @@ public partial class MainForm : Form
Player.WasInitialSizeSet = true; 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 = WinApiHelp.GetWorkingArea(Handle, screen.WorkingArea); Rectangle workingArea = GetWorkingArea(Handle, screen.WorkingArea);
int maxHeight = workingArea.Height - (Height - ClientSize.Height) - 2; int maxHeight = workingArea.Height - (Height - ClientSize.Height) - 2;
int maxWidth = workingArea.Width - (Width - ClientSize.Width); int maxWidth = workingArea.Width - (Width - ClientSize.Width);
@@ -622,71 +631,108 @@ public partial class MainForm : Form
{ {
if (height < maxHeight * Player.AutofitSmaller) if (height < maxHeight * Player.AutofitSmaller)
{ {
height = Convert.ToInt32(maxHeight * Player.AutofitSmaller); height = (int)(maxHeight * Player.AutofitSmaller);
width = Convert.ToInt32(height * startWidth / (double)startHeight); width = (int)Math.Ceiling(height * startWidth / (double)startHeight);
} }
if (height > maxHeight * Player.AutofitLarger) if (height > maxHeight * Player.AutofitLarger)
{ {
height = Convert.ToInt32(maxHeight * Player.AutofitLarger); height = (int)(maxHeight * Player.AutofitLarger);
width = Convert.ToInt32(height * startWidth / (double)startHeight); width = (int)Math.Ceiling(height * startWidth / (double)startHeight);
} }
} }
if (width > maxWidth) if (width > maxWidth)
{ {
width = maxWidth; width = maxWidth;
height = (int)Math.Ceiling(width * startHeight / (double)startWidth); height = (int)Math.Floor(width * startHeight / (double)startWidth);
} }
if (height > maxHeight) if (height > maxHeight)
{ {
height = maxHeight; height = maxHeight;
width = Convert.ToInt32(height * startWidth / (double)startHeight); width = (int)Math.Ceiling(height * startWidth / (double)startHeight);
} }
if (height < maxHeight * 0.1) if (height < maxHeight * 0.1)
{ {
height = Convert.ToInt32(maxHeight * 0.1); height = (int)(maxHeight * 0.1);
width = Convert.ToInt32(height * startWidth / (double)startHeight); width = (int)Math.Ceiling(height * startWidth / (double)startHeight);
} }
Point middlePos = new Point(Left + Width / 2, Top + Height / 2); Point middlePos = new Point(Left + Width / 2, Top + Height / 2);
var rect = new Rect(new Rectangle(screen.Bounds.X, screen.Bounds.Y, width, height)); var rect = new RECT(new Rectangle(screen.Bounds.X, screen.Bounds.Y, width, height));
WinApiHelp.AddWindowBorders(Handle, ref rect, GetDpi(Handle));
int left = middlePos.X - rect.Width / 2; AddWindowBorders(Handle, ref rect, GetDpi(Handle), !Player.TitleBar);
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); Rectangle currentRect = new Rectangle(Left, Top, Width, Height);
if (GetHorizontalLocation(screen) == -1) left = Left; 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 = Top;
if (GetVerticalLocation(screen) == 1) top = currentRect.Bottom - rect.Height; if (GetVerticalLocation(screen) == 1) top = currentRect.Bottom - height;
Screen[] screens = Screen.AllScreens; Screen[] screens = Screen.AllScreens;
int minLeft = screens.Select(val => WinApiHelp.GetWorkingArea(Handle, val.WorkingArea).X).Min(); int minLeft = screens.Select(val => GetWorkingArea(Handle, val.WorkingArea).X).Min();
int maxRight = screens.Select(val => WinApiHelp.GetWorkingArea(Handle, val.WorkingArea).Right).Max(); int maxRight = screens.Select(val => GetWorkingArea(Handle, val.WorkingArea).Right).Max();
int minTop = screens.Select(val => WinApiHelp.GetWorkingArea(Handle, val.WorkingArea).Y).Min(); int minTop = screens.Select(val => GetWorkingArea(Handle, val.WorkingArea).Y).Min();
int maxBottom = screens.Select(val => WinApiHelp.GetWorkingArea(Handle, val.WorkingArea).Bottom).Max(); int maxBottom = screens.Select(val => GetWorkingArea(Handle, val.WorkingArea).Bottom).Max();
if (load && CommandLine.Contains("geometry"))
{
string geometryString = CommandLine.GetValue("geometry");
var geometry = ParseGeometry(geometryString, 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) if (left < minLeft)
left = minLeft; left = minLeft;
if (left + rect.Width > maxRight) if (left + width > maxRight)
left = maxRight - rect.Width; left = maxRight - width;
if (top < minTop) if (top < minTop)
top = minTop; top = minTop;
if (top + rect.Height > maxBottom) if (top + height > maxBottom)
top = maxBottom - rect.Height; top = maxBottom - height;
uint SWP_NOACTIVATE = 0x0010; 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) public void CycleFullscreen(bool enabled)
@@ -734,7 +780,7 @@ public partial class MainForm : Form
public int GetHorizontalLocation(Screen screen) public int GetHorizontalLocation(Screen screen)
{ {
Rectangle workingArea = WinApiHelp.GetWorkingArea(Handle, screen.WorkingArea); Rectangle workingArea = GetWorkingArea(Handle, screen.WorkingArea);
Rectangle rect = new Rectangle(Left - workingArea.X, Top - workingArea.Y, Width, Height); Rectangle rect = new Rectangle(Left - workingArea.X, Top - workingArea.Y, Width, Height);
if (workingArea.Width / (float)Width < 1.1) if (workingArea.Width / (float)Width < 1.1)
@@ -751,7 +797,7 @@ public partial class MainForm : Form
public int GetVerticalLocation(Screen screen) public int GetVerticalLocation(Screen screen)
{ {
Rectangle workingArea = WinApiHelp.GetWorkingArea(Handle, screen.WorkingArea); Rectangle workingArea = GetWorkingArea(Handle, screen.WorkingArea);
Rectangle rect = new Rectangle(Left - workingArea.X, Top - workingArea.Y, Width, Height); Rectangle rect = new Rectangle(Left - workingArea.X, Top - workingArea.Y, Width, Height);
if (workingArea.Height / (float)Height < 1.1) if (workingArea.Height / (float)Height < 1.1)
@@ -970,6 +1016,9 @@ public partial class MainForm : Form
m.Result = SendMessage(MpvWindowHandle, m.Msg, m.WParam, m.LParam); m.Result = SendMessage(MpvWindowHandle, m.Msg, m.WParam, m.LParam);
} }
break; break;
case 0x001A: // WM_SETTINGCHANGE
UpdateDarkMode();
break;
case 0x51: // WM_INPUTLANGCHANGE case 0x51: // WM_INPUTLANGCHANGE
ActivateKeyboardLayout(m.LParam, 0x00000100u /*KLF_SETFORPROCESS*/); ActivateKeyboardLayout(m.LParam, 0x00000100u /*KLF_SETFORPROCESS*/);
break; break;
@@ -1009,16 +1058,45 @@ public partial class MainForm : Form
if (!WasShown) if (!WasShown)
break; break;
Rect rect = Marshal.PtrToStructure<Rect>(m.LParam); RECT rect = Marshal.PtrToStructure<RECT>(m.LParam);
SetWindowPos(Handle, IntPtr.Zero, rect.Left, rect.Top, rect.Width, rect.Height, 0); SetWindowPos(Handle, IntPtr.Zero, rect.Left, rect.Top, rect.Width, rect.Height, 0);
} }
break; break;
case 0x0112: // WM_SYSCOMMAND
{
// with title-bar=no when the window is restored from minimizing the height is too high
if (!Player.TitleBar)
{
int SC_MINIMIZE = 0xF020;
if (m.WParam == (nint)SC_MINIMIZE)
{
MaximumSize = Size;
_maxSizeSet = true;
}
}
}
break;
case 0x0083: // WM_NCCALCSIZE
if ((int)m.WParam == 1 && !Player.TitleBar && !IsFullscreen)
{
var nccalcsize_params = Marshal.PtrToStructure<NCCALCSIZE_PARAMS>(m.LParam);
RECT[] rects = nccalcsize_params.rgrc;
rects[0].Top = rects[0].Top - GetTitleBarHeight(Handle, GetDpi(Handle));
Marshal.StructureToPtr(nccalcsize_params, m.LParam, false);
}
break;
case 0x231: // WM_ENTERSIZEMOVE
case 0x005: // WM_SIZE
if (Player.SnapWindow)
SnapManager.OnSizeAndEnterSizeMove(this);
break;
case 0x214: // WM_SIZING case 0x214: // WM_SIZING
if (Player.KeepaspectWindow) if (Player.KeepaspectWindow)
{ {
Rect rc = Marshal.PtrToStructure<Rect>(m.LParam); RECT rc = Marshal.PtrToStructure<RECT>(m.LParam);
Rect r = rc; RECT r = rc;
WinApiHelp.SubtractWindowBorders(Handle, ref r, GetDpi(Handle)); SubtractWindowBorders(Handle, ref r, GetDpi(Handle), !Player.TitleBar);
int c_w = r.Right - r.Left, c_h = r.Bottom - r.Top; int c_w = r.Right - r.Left, c_h = r.Bottom - r.Top;
Size videoSize = Player.VideoSize; Size videoSize = Player.VideoSize;
@@ -1026,48 +1104,25 @@ public partial class MainForm : Form
if (videoSize == Size.Empty) if (videoSize == Size.Empty)
videoSize = new Size(16, 9); videoSize = new Size(16, 9);
float aspect = videoSize.Width / (float)videoSize.Height; double aspect = videoSize.Width / (double)videoSize.Height;
int d_w = (int)(c_h * aspect - c_w); int d_w = (int)Math.Ceiling(c_h * aspect - c_w);
int d_h = (int)(c_w / aspect - c_h); int d_h = (int)Math.Floor(c_w / aspect - c_h);
int[] d_corners = { d_w, d_h, -d_w, -d_h }; int[] d_corners = { d_w, d_h, -d_w, -d_h };
int[] corners = { rc.Left, rc.Top, rc.Right, rc.Bottom }; int[] corners = { rc.Left, rc.Top, rc.Right, rc.Bottom };
int corner = WinApiHelp.GetResizeBorder(m.WParam.ToInt32()); int corner = GetResizeBorder(m.WParam.ToInt32());
if (corner >= 0) if (corner >= 0)
corners[corner] -= d_corners[corner]; corners[corner] -= d_corners[corner];
Marshal.StructureToPtr(new Rect(corners[0], corners[1], corners[2], corners[3]), m.LParam, false); Marshal.StructureToPtr(new RECT(corners[0], corners[1], corners[2], corners[3]), m.LParam, false);
m.Result = new IntPtr(1); m.Result = new IntPtr(1);
} }
return; return;
case 0x4A: // WM_COPYDATA
{
var copyData = (CopyDataStruct)m.GetLParam(typeof(CopyDataStruct))!;
string[] args = copyData.lpData.Split('\n');
string mode = args[0];
args = args.Skip(1).ToArray();
switch (mode)
{
case "single":
Player.LoadFiles(args, true, false);
break;
case "queue":
foreach (string file in args)
Player.CommandV("loadfile", file, "append");
break;
case "command":
Player.Command(args[0]);
break;
}
Activate();
}
return;
case 0x84: // WM_NCHITTEST case 0x84: // WM_NCHITTEST
// resize borderless window // resize borderless window
if (!Player.Border && !Player.Fullscreen) { if ((!Player.Border || !Player.TitleBar) && !Player.Fullscreen)
{
const int HTCLIENT = 1; const int HTCLIENT = 1;
const int HTLEFT = 10; const int HTLEFT = 10;
const int HTRIGHT = 11; const int HTRIGHT = 11;
@@ -1106,11 +1161,30 @@ public partial class MainForm : Form
return; return;
} }
break; break;
case 0x231: // WM_ENTERSIZEMOVE case 0x4A: // WM_COPYDATA
case 0x005: // WM_SIZE {
if (Player.SnapWindow) var copyData = (CopyDataStruct)m.GetLParam(typeof(CopyDataStruct))!;
SnapManager.OnSizeAndEnterSizeMove(this); string[] args = copyData.lpData.Split('\n');
string mode = args[0];
args = args.Skip(1).ToArray();
switch (mode)
{
case "single":
Player.LoadFiles(args, true, false);
break; break;
case "queue":
foreach (string file in args)
Player.CommandV("loadfile", file, "append");
break;
case "command":
Player.Command(args[0]);
break;
}
Activate();
}
return;
case 0x216: // WM_MOVING case 0x216: // WM_MOVING
if (Player.SnapWindow) if (Player.SnapWindow)
SnapManager.OnMoving(ref m); SnapManager.OnMoving(ref m);
@@ -1128,6 +1202,25 @@ public partial class MainForm : Form
base.WndProc(ref m); base.WndProc(ref m);
} }
protected override void OnActivated(EventArgs e)
{
base.OnActivated(e);
if (_maxSizeSet)
{
TaskHelp.Run(() => {
Thread.Sleep(200);
BeginInvoke(() => {
if (!IsDisposed && !Disposing)
{
MaximumSize = new Size(int.MaxValue, int.MaxValue);
_maxSizeSet = false;
}
});
});
}
}
void CursorTimer_Tick(object sender, EventArgs e) void CursorTimer_Tick(object sender, EventArgs e)
{ {
if (IsCursorPosDifferent(_lastCursorPosition)) if (IsCursorPosDifferent(_lastCursorPosition))
@@ -1211,6 +1304,20 @@ public partial class MainForm : Form
}); });
} }
void PropChangeTitleBar(bool enabled)
{
if (enabled == Player.TitleBar)
return;
Player.TitleBar = enabled;
BeginInvoke(() => {
SetSize(ClientSize.Width, ClientSize.Height, Screen.FromControl(this), false);
Height += 1;
Height -= 1;
});
}
void Player_Pause() void Player_Pause()
{ {
if (_taskbar != null && Player.TaskbarProgress) if (_taskbar != null && Player.TaskbarProgress)
@@ -1220,10 +1327,8 @@ public partial class MainForm : Form
protected override void OnLoad(EventArgs e) protected override void OnLoad(EventArgs e)
{ {
base.OnLoad(e); base.OnLoad(e);
if (Player.GPUAPI != "vulkan")
Player.VideoSizeAutoResetEvent.WaitOne(App.StartThreshold);
_lastCycleFullscreen = Environment.TickCount; _lastCycleFullscreen = Environment.TickCount;
SetFormPosAndSize(); SetFormPosAndSize(false, true, true);
} }
protected override void OnLostFocus(EventArgs e) protected override void OnLostFocus(EventArgs e)
@@ -1236,9 +1341,6 @@ public partial class MainForm : Form
{ {
base.OnShown(e); base.OnShown(e);
if (Player.GPUAPI == "vulkan")
Init();
if (WindowState == FormWindowState.Maximized) if (WindowState == FormWindowState.Maximized)
Player.SetPropertyBool("window-maximized", true); Player.SetPropertyBool("window-maximized", true);
@@ -1250,14 +1352,8 @@ public partial class MainForm : Form
InitAndBuildContextMenu(); InitAndBuildContextMenu();
Cursor.Position = new Point(Cursor.Position.X + 1, Cursor.Position.Y); Cursor.Position = new Point(Cursor.Position.X + 1, Cursor.Position.Y);
GlobalHotkey.RegisterGlobalHotkeys(Handle); GlobalHotkey.RegisterGlobalHotkeys(Handle);
WasShown = true;
StrongReferenceMessenger.Default.Send(new MainWindowIsLoadedMessage()); StrongReferenceMessenger.Default.Send(new MainWindowIsLoadedMessage());
WasShown = true;
TaskHelp.Run(() => {
System.Windows.Application.Current.Dispatcher.BeginInvoke(() => {
WinMpvHelp.AddToPath();
}, DispatcherPriority.Background);
});
} }
void ContextMenu_Closed(object sender, System.Windows.RoutedEventArgs e) => MenuAutoResetEvent.Set(); void ContextMenu_Closed(object sender, System.Windows.RoutedEventArgs e) => MenuAutoResetEvent.Set();
@@ -1346,10 +1442,12 @@ public partial class MainForm : Form
{ {
base.OnDragDrop(e); base.OnDragDrop(e);
bool append = ModifierKeys == Keys.Shift;
if (e.Data!.GetDataPresent(DataFormats.FileDrop)) if (e.Data!.GetDataPresent(DataFormats.FileDrop))
Player.LoadFiles(e.Data.GetData(DataFormats.FileDrop) as string[], true, false); Player.LoadFiles(e.Data.GetData(DataFormats.FileDrop) as string[], true, append);
else if (e.Data.GetDataPresent(DataFormats.Text)) else if (e.Data.GetDataPresent(DataFormats.Text))
Player.LoadFiles(new[] { e.Data.GetData(DataFormats.Text)!.ToString()! }, true, false); Player.LoadFiles(new[] { e.Data.GetData(DataFormats.Text)!.ToString()! }, true, append);
} }
protected override void OnKeyDown(KeyEventArgs e) protected override void OnKeyDown(KeyEventArgs e)
@@ -1389,7 +1487,7 @@ public partial class MainForm : Form
public static int GetDpi(IntPtr hwnd) public static int GetDpi(IntPtr hwnd)
{ {
if (Environment.OSVersion.Version >= WinApiHelp.WindowsTen1607 && hwnd != IntPtr.Zero) if (Environment.OSVersion.Version >= WindowsTen1607 && hwnd != IntPtr.Zero)
return GetDpiForWindow(hwnd); return GetDpiForWindow(hwnd);
else else
using (Graphics gx = Graphics.FromHwnd(hwnd)) using (Graphics gx = Graphics.FromHwnd(hwnd))

View File

@@ -51,7 +51,7 @@ public class SnapManager
if (Handle == IntPtr.Zero) if (Handle == IntPtr.Zero)
return; return;
WinApi.Rect boundsLtrb = Marshal.PtrToStructure<WinApi.Rect>(m.LParam); WinApi.RECT boundsLtrb = Marshal.PtrToStructure<WinApi.RECT>(m.LParam);
Rectangle bounds = boundsLtrb.ToRectangle(); Rectangle bounds = boundsLtrb.ToRectangle();
// This is where the window _would_ be located if snapping // This is where the window _would_ be located if snapping
// had not occurred. This prevents the cursor from sliding // had not occurred. This prevents the cursor from sliding
@@ -62,7 +62,7 @@ public class SnapManager
bounds.Width, bounds.Width,
bounds.Height); bounds.Height);
FindSnap(ref effectiveBounds); FindSnap(ref effectiveBounds);
WinApi.Rect newLtrb = WinApi.Rect.FromRectangle(effectiveBounds); WinApi.RECT newLtrb = WinApi.RECT.FromRectangle(effectiveBounds);
Marshal.StructureToPtr(newLtrb, m.LParam, false); Marshal.StructureToPtr(newLtrb, m.LParam, false);
m.Result = new IntPtr(1); m.Result = new IntPtr(1);
} }

View File

@@ -10,7 +10,6 @@ namespace MpvNet;
public class AppClass public class AppClass
{ {
public List<string> TempFiles { get; } = new (); public List<string> TempFiles { get; } = new ();
public Dictionary<string, string> CommandLineArguments { get; } = new ();
public string ConfPath { get => Player.ConfigFolder + "mpvnet.conf"; } public string ConfPath { get => Player.ConfigFolder + "mpvnet.conf"; }
public string ProcessInstance { get; set; } = "single"; public string ProcessInstance { get; set; } = "single";
@@ -31,7 +30,6 @@ public class AppClass
public bool RememberVolume { get; set; } = true; public bool RememberVolume { get; set; } = true;
public bool RememberWindowPosition { get; set; } public bool RememberWindowPosition { get; set; }
public int StartThreshold { get; set; } = 1500;
public int RecentCount { get; set; } = 15; public int RecentCount { get; set; } = 15;
public float AutofitAudio { get; set; } = 0.7f; public float AutofitAudio { get; set; } = 0.7f;
@@ -81,7 +79,7 @@ public class AppClass
public static string About => "Copyright (C) 2000-2023 mpv.net/mpv/mplayer\n" + public static string About => "Copyright (C) 2000-2023 mpv.net/mpv/mplayer\n" +
$"{AppInfo.Product} {AppInfo.Version}" + GetLastWriteTime(Environment.ProcessPath!) + "\n" + $"{AppInfo.Product} {AppInfo.Version}" + GetLastWriteTime(Environment.ProcessPath!) + "\n" +
$"{Player.GetPropertyString("mpv-version")}" + GetLastWriteTime(Folder.Startup + "libmpv-2.dll") + "\n" + $"{Player.GetPropertyString("mpv-version")}" + GetLastWriteTime(Folder.Startup + "libmpv-2.dll") + "\n" +
$"ffmpeg {Player.GetPropertyString("ffmpeg-version")}\n" + "\nGPL v2 License"; $"ffmpeg {Player.GetPropertyString("ffmpeg-version")}\n" + "GPL v2 License";
static string GetLastWriteTime(string path) static string GetLastWriteTime(string path)
{ {
@@ -155,7 +153,6 @@ public class AppClass
case "remember-volume": RememberVolume = value == "yes"; return true; case "remember-volume": RememberVolume = value == "yes"; return true;
case "remember-window-position": RememberWindowPosition = value == "yes"; return true; case "remember-window-position": RememberWindowPosition = value == "yes"; return true;
case "start-size": StartSize = value; 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; case "video-file-extensions": FileTypes.Video = value.Split(" ,;".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); return true;
default: default:

73
src/MpvNet/CommandLine.cs Normal file
View 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 "";
}
}

View File

@@ -17,8 +17,9 @@ public static class InputHelp
new (_("File"), _("Add external subtitle files..."), "script-message-to mpvnet load-sub", "Alt+s"), new (_("File"), _("Add external subtitle files..."), "script-message-to mpvnet load-sub", "Alt+s"),
new (_("File"), "-"), new (_("File"), "-"),
new (_("File"), _("Add files to playlist..."), "script-message-to mpvnet open-files append"), new (_("File"), _("Add files to playlist..."), "script-message-to mpvnet open-files append"),
new (_("File"), _("Recent Files")), new (_("File"), _("Add files/URLs to playlist from clipboard"), "script-message-to mpvnet open-clipboard append", "Ctrl+Shift+v"),
new (_("File"), "-"), new (_("File"), "-"),
new (_("File"), _("Recent Files")),
new (_("File"), _("Exit"), "quit", "Esc"), new (_("File"), _("Exit"), "quit", "Esc"),
new (_("Playback"), _("Play/Pause"), "script-message-to mpvnet play-pause", "Space"), new (_("Playback"), _("Play/Pause"), "script-message-to mpvnet play-pause", "Space"),
@@ -125,8 +126,6 @@ public static class InputHelp
new (_("View") + " > " + _("More"), _("Show Console"), "script-binding console/enable", "`"), 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 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 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 (_("View") + " > " + _("More"), _("Show Bindings"), "script-message-to mpvnet show-bindings"),
new (_("Window"), _("Fullscreen"), "cycle fullscreen", "Enter"), new (_("Window"), _("Fullscreen"), "cycle fullscreen", "Enter"),
@@ -286,6 +285,9 @@ public static class InputHelp
if (string.IsNullOrEmpty(content)) if (string.IsNullOrEmpty(content))
return bindings; return bindings;
if (content.Contains('\t'))
content = content.Replace('\t', ' ');
foreach (string it in content.Split('\n')) foreach (string it in content.Split('\n'))
{ {
string line = it.Trim(); string line = it.Trim();

View File

@@ -64,7 +64,7 @@ public class MpvClient
OnEndFile(data); OnEndFile(data);
} }
break; break;
case mpv_event_id.MPV_EVENT_FILE_LOADED: case mpv_event_id.MPV_EVENT_FILE_LOADED: // triggered after MPV_EVENT_START_FILE
OnFileLoaded(); OnFileLoaded();
break; break;
case mpv_event_id.MPV_EVENT_PROPERTY_CHANGE: case mpv_event_id.MPV_EVENT_PROPERTY_CHANGE:
@@ -82,7 +82,7 @@ public class MpvClient
case mpv_event_id.MPV_EVENT_COMMAND_REPLY: case mpv_event_id.MPV_EVENT_COMMAND_REPLY:
OnCommandReply(); OnCommandReply();
break; break;
case mpv_event_id.MPV_EVENT_START_FILE: case mpv_event_id.MPV_EVENT_START_FILE: // triggered before MPV_EVENT_FILE_LOADED
OnStartFile(); OnStartFile();
break; break;
case mpv_event_id.MPV_EVENT_AUDIO_RECONFIG: case mpv_event_id.MPV_EVENT_AUDIO_RECONFIG:

View File

@@ -36,6 +36,7 @@ public class MainPlayer : MpvClient
public bool Paused { get; set; } public bool Paused { get; set; }
public bool SnapWindow { get; set; } public bool SnapWindow { get; set; }
public bool TaskbarProgress { get; set; } = true; public bool TaskbarProgress { get; set; } = true;
public bool TitleBar { get; set; } = true;
public bool WasInitialSizeSet; public bool WasInitialSizeSet;
public bool WindowMaximized { get; set; } public bool WindowMaximized { get; set; }
public bool WindowMinimized { get; set; } public bool WindowMinimized { get; set; }
@@ -50,7 +51,6 @@ public class MainPlayer : MpvClient
public float AutofitLarger { get; set; } = 0.8f; public float AutofitLarger { get; set; } = 0.8f;
public AutoResetEvent ShutdownAutoResetEvent { get; } = new AutoResetEvent(false); public AutoResetEvent ShutdownAutoResetEvent { get; } = new AutoResetEvent(false);
public AutoResetEvent VideoSizeAutoResetEvent { get; } = new AutoResetEvent(false);
public nint MainHandle { get; set; } public nint MainHandle { get; set; }
public List<MediaTrack> MediaTracks { get; set; } = new List<MediaTrack>(); public List<MediaTrack> MediaTracks { get; set; } = new List<MediaTrack>();
public List<TimeSpan> BluRayTitles { get; } = new List<TimeSpan>(); public List<TimeSpan> BluRayTitles { get; } = new List<TimeSpan>();
@@ -64,7 +64,7 @@ public class MainPlayer : MpvClient
public event Action<int>? PlaylistPosChanged; public event Action<int>? PlaylistPosChanged;
public event Action<Size>? VideoSizeChanged; public event Action<Size>? VideoSizeChanged;
public void Init(IntPtr formHandle) public void Init(IntPtr formHandle, bool processCommandLineArguments = true)
{ {
App.ApplyShowMenuFix(); App.ApplyShowMenuFix();
@@ -110,11 +110,12 @@ public class MainPlayer : MpvClient
if (!string.IsNullOrEmpty(UsedInputConfContent)) if (!string.IsNullOrEmpty(UsedInputConfContent))
SetPropertyString("input-conf", @"memory://" + UsedInputConfContent); SetPropertyString("input-conf", @"memory://" + UsedInputConfContent);
if (processCommandLineArguments)
ProcessCommandLineArgs(); 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); string fullPath = System.IO.Path.GetFullPath(configDir);
App.InputConf.Path = fullPath.AddSep() + "input.conf"; App.InputConf.Path = fullPath.AddSep() + "input.conf";
string content = App.InputConf.GetContent(); string content = App.InputConf.GetContent();
@@ -130,10 +131,6 @@ public class MainPlayer : MpvClient
if (err < 0) if (err < 0)
throw new Exception("mpv_initialize error" + BR2 + GetError(err) + BR); throw new Exception("mpv_initialize error" + BR2 + GetError(err) + BR);
SetPropertyString("user-data/frontend/name", "mpv.net");
SetPropertyString("user-data/frontend/version", AppInfo.Version.ToString());
SetPropertyString("user-data/frontend/process-path", Environment.ProcessPath!);
string idle = GetPropertyString("idle"); string idle = GetPropertyString("idle");
App.Exit = idle == "no" || idle == "once"; App.Exit = idle == "no" || idle == "once";
@@ -151,16 +148,24 @@ public class MainPlayer : MpvClient
// this means Lua scripts that use idle might not work correctly // this means Lua scripts that use idle might not work correctly
SetPropertyString("idle", "yes"); SetPropertyString("idle", "yes");
ObservePropertyString("path", value => Path = value); SetPropertyString("user-data/frontend/name", "mpv.net");
SetPropertyString("user-data/frontend/version", AppInfo.Version.ToString());
SetPropertyString("user-data/frontend/process-path", Environment.ProcessPath!);
ObservePropertyBool("pause", value => { ObservePropertyBool("pause", value => {
Paused = value; Paused = value;
Pause?.Invoke(); Pause?.Invoke();
}); });
ObservePropertyInt("video-rotate", value => { VideoRotate = GetPropertyInt("video-rotate");
ObservePropertyInt("video-rotate", value =>
{
if (VideoRotate != value)
{
VideoRotate = value; VideoRotate = value;
UpdateVideoSize("dwidth", "dheight"); UpdateVideoSize("dwidth", "dheight");
}
}); });
ObservePropertyInt("playlist-pos", value => { ObservePropertyInt("playlist-pos", value => {
@@ -172,9 +177,6 @@ public class MainPlayer : MpvClient
CommandV("quit"); CommandV("quit");
}); });
if (!GetPropertyBool("osd-scale-by-window"))
App.StartThreshold = 0;
Initialized?.Invoke(); Initialized?.Invoke();
} }
@@ -220,6 +222,7 @@ public class MainPlayer : MpvClient
case "vo": VO = value!; break; case "vo": VO = value!; break;
case "window-maximized": WindowMaximized = value == "yes"; break; case "window-maximized": WindowMaximized = value == "yes"; break;
case "window-minimized": WindowMinimized = value == "yes"; break; case "window-minimized": WindowMinimized = value == "yes"; break;
case "title-bar": TitleBar = value == "yes"; break;
} }
if (AutofitLarger > 1) if (AutofitLarger > 1)
@@ -315,19 +318,18 @@ public class MainPlayer : MpvClient
void UpdateVideoSize(string w, string h) void UpdateVideoSize(string w, string h)
{ {
Size size = new Size(GetPropertyInt(w), GetPropertyInt(h)); if (string.IsNullOrEmpty(Path))
if (size.Width == 0 || size.Height == 0)
return; return;
Size size = new Size(GetPropertyInt(w), GetPropertyInt(h));
if (VideoRotate == 90 || VideoRotate == 270) if (VideoRotate == 90 || VideoRotate == 270)
size = new Size(size.Height, size.Width); size = new Size(size.Height, size.Width);
if (VideoSize != size) if (size != VideoSize && size != Size.Empty)
{ {
VideoSize = size; VideoSize = size;
VideoSizeChanged?.Invoke(size); VideoSizeChanged?.Invoke(size);
VideoSizeAutoResetEvent.Set();
} }
} }
@@ -357,24 +359,27 @@ public class MainPlayer : MpvClient
base.OnLogMessage(data); base.OnLogMessage(data);
} }
protected override void OnVideoReconfig()
{
UpdateVideoSize("dwidth", "dheight");
base.OnVideoReconfig();
}
protected override void OnEndFile(mpv_event_end_file data) protected override void OnEndFile(mpv_event_end_file data)
{ {
base.OnEndFile(data); base.OnEndFile(data);
FileEnded = true; FileEnded = true;
} }
protected override void OnVideoReconfig()
{
UpdateVideoSize("dwidth", "dheight");
base.OnVideoReconfig();
}
// executed before OnFileLoaded
protected override void OnStartFile() protected override void OnStartFile()
{ {
Path = GetPropertyString("path");
base.OnStartFile(); base.OnStartFile();
TaskHelp.Run(LoadFolder); TaskHelp.Run(LoadFolder);
} }
// executed after OnStartFile
protected override void OnFileLoaded() protected override void OnFileLoaded()
{ {
Duration = TimeSpan.FromSeconds(GetPropertyDouble("duration")); Duration = TimeSpan.FromSeconds(GetPropertyDouble("duration"));
@@ -382,13 +387,8 @@ public class MainPlayer : MpvClient
if (App.StartSize == "video") if (App.StartSize == "video")
WasInitialSizeSet = false; 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"); UpdateVideoSize("width", "height");
VideoSizeAutoResetEvent.Set();
}
TaskHelp.Run(UpdateTracks); TaskHelp.Run(UpdateTracks);
@@ -417,75 +417,43 @@ public class MainPlayer : MpvClient
public void ProcessCommandLineArgs() public void ProcessCommandLineArgs()
{ {
foreach (string i in Environment.GetCommandLineArgs().Skip(1)) foreach (var pair in CommandLine.Arguments)
{ {
string arg = i; if (pair.Name.EndsWith("-add") ||
pair.Name.EndsWith("-set") ||
pair.Name.EndsWith("-pre") ||
pair.Name.EndsWith("-clr") ||
pair.Name.EndsWith("-append") ||
pair.Name.EndsWith("-remove") ||
pair.Name.EndsWith("-toggle"))
if (!arg.StartsWith("--"))
continue; continue;
if (arg == "--profile=help") ProcessProperty(pair.Name, pair.Value);
{
Console.WriteLine(GetProfiles()); if (!App.ProcessProperty(pair.Name, pair.Value))
continue; 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-", "--"); if (pair.Name.EndsWith("-add"))
arg += "=no"; CommandV("change-list", pair.Name[..^4], "add", pair.Value);
} else if (pair.Name.EndsWith("-set"))
else CommandV("change-list", pair.Name[..^4], "set", pair.Value);
arg += "=yes"; else if (pair.Name.EndsWith("-append"))
} CommandV("change-list", pair.Name[..^7], "append", pair.Value);
else if (pair.Name.EndsWith("-pre"))
string left = arg[2..arg.IndexOf("=")]; CommandV("change-list", pair.Name[..^4], "pre", pair.Value);
string right = arg[(left.Length + 3)..]; else if (pair.Name.EndsWith("-clr"))
CommandV("change-list", pair.Name[..^4], "clr", "");
if (string.IsNullOrEmpty(left)) else if (pair.Name.EndsWith("-remove"))
continue; CommandV("change-list", pair.Name[..^7], "remove", pair.Value);
else if (pair.Name.EndsWith("-toggle"))
switch (left) CommandV("change-list", pair.Name[..^7], "toggle", pair.Value);
{
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;
}
App.CommandLineArguments[left] = right;
ProcessProperty(left, right);
if (!App.ProcessProperty(left, right))
SetPropertyString(left, right);
} }
} }
@@ -499,19 +467,13 @@ public class MainPlayer : MpvClient
files.Add(arg); files.Add(arg);
LoadFiles(files.ToArray(), !App.Queue, false || App.Queue); LoadFiles(files.ToArray(), !App.Queue, App.Queue);
if (App.CommandLine.Contains("--shuffle")) if (App.CommandLine.Contains("--shuffle"))
{ {
Command("playlist-shuffle"); Command("playlist-shuffle");
SetPropertyInt("playlist-pos", 0); SetPropertyInt("playlist-pos", 0);
} }
if (files.Count == 0 || files[0].Contains("://"))
{
VideoSizeChanged?.Invoke(VideoSize);
VideoSizeAutoResetEvent.Set();
}
} }
public DateTime LastLoad; public DateTime LastLoad;

View File

@@ -0,0 +1,7 @@
{
"profiles": {
"MpvNet": {
"commandName": "Project"
}
}
}

View File

@@ -18,6 +18,7 @@ public class AppSettings
public Size WindowSize; public Size WindowSize;
public string ConfigEditorSearch = "Video:"; public string ConfigEditorSearch = "Video:";
public string Mute = "no"; public string Mute = "no";
public string StartupFolder = "";
} }
class SettingsManager class SettingsManager

View File

@@ -1,4 +1,5 @@
namespace MpvNet.Windows; 
namespace MpvNet;
public class StringPair public class StringPair
{ {

View File

@@ -11,12 +11,14 @@ AppVersion={#MyAppVersion}
AppPublisher=Frank Skare (stax76) AppPublisher=Frank Skare (stax76)
ArchitecturesInstallIn64BitMode=x64 ArchitecturesInstallIn64BitMode=x64
Compression=lzma2 Compression=lzma2
DefaultDirName={commonpf}\{#MyAppName} DefaultDirName={autopf}\{#MyAppName}
OutputBaseFilename=mpv.net-v{#MyAppVersion}-setup OutputBaseFilename=mpv.net-v{#MyAppVersion}-setup
OutputDir=E:\Desktop OutputDir=E:\Desktop
DefaultGroupName={#MyAppName} DefaultGroupName={#MyAppName}
SetupIconFile=..\..\MpvNet.Windows\mpv-icon.ico SetupIconFile=..\..\MpvNet.Windows\mpv-icon.ico
UninstallDisplayIcon={app}\{#MyAppExeName} UninstallDisplayIcon={app}\{#MyAppExeName}
PrivilegesRequired=admin
PrivilegesRequiredOverridesAllowed=dialog
[Icons] [Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"