#334 New support of the mpv option snap-window
This commit is contained in:
@@ -4,8 +4,9 @@
|
|||||||
- New tutorial: [Extending mpv and mpv.net via Lua scripting](https://github.com/stax76/mpv.net/wiki/Extending-mpv-and-mpv.net-via-Lua-scripting)
|
- New tutorial: [Extending mpv and mpv.net via Lua scripting](https://github.com/stax76/mpv.net/wiki/Extending-mpv-and-mpv.net-via-Lua-scripting)
|
||||||
- New options `autofit-image` and `autofit-audio`, like autofit but used for image and audio files. Default 80.
|
- New options `autofit-image` and `autofit-audio`, like autofit but used for image and audio files. Default 80.
|
||||||
- New [auto-mode](https://github.com/stax76/mpv-scripts) script to use mpv and mpv.net as image viewer and audio player.
|
- New [auto-mode](https://github.com/stax76/mpv-scripts) script to use mpv and mpv.net as image viewer and audio player.
|
||||||
|
- New support of the mpv option `snap-window`.
|
||||||
- Fix long commands causing key bindings not visible in the command palette.
|
- Fix long commands causing key bindings not visible in the command palette.
|
||||||
- Fix compatibility with mpv-osc-tethys, which is a new osc script.
|
- Fix script compatibility with mordenx and mpv-osc-tethys.
|
||||||
- Fix borderless window not resizable with mouse.
|
- Fix borderless window not resizable with mouse.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -434,12 +434,6 @@ Window size is remembered in the current session.
|
|||||||
**always**
|
**always**
|
||||||
Window size is always remembered.
|
Window size is always remembered.
|
||||||
|
|
||||||
#### --start-threshold=\<milliseconds\>
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
#### --minimum-aspect-ratio=\<float\>
|
#### --minimum-aspect-ratio=\<float\>
|
||||||
|
|
||||||
Minimum aspect ratio, if the AR is smaller than the defined value then
|
Minimum aspect ratio, if the AR is smaller than the defined value then
|
||||||
@@ -450,6 +444,11 @@ with cover art. Default: 0
|
|||||||
|
|
||||||
Save the window position on exit. Default: no
|
Save the window position on exit. Default: no
|
||||||
|
|
||||||
|
#### --start-threshold=\<milliseconds\>
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
### Playback
|
### Playback
|
||||||
|
|
||||||
@@ -766,6 +765,7 @@ https://mpv.io/manual/master/#window
|
|||||||
- [keepaspect-window](https://mpv.io/manual/master/#options-keepaspect-window)
|
- [keepaspect-window](https://mpv.io/manual/master/#options-keepaspect-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)
|
||||||
- [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)
|
||||||
@@ -774,9 +774,12 @@ https://mpv.io/manual/master/#window
|
|||||||
|
|
||||||
**Partly implemented are:**
|
**Partly implemented are:**
|
||||||
|
|
||||||
- [autofit-larger](https://mpv.io/manual/master/#options-autofit-larger)
|
- [autofit-larger](https://mpv.io/manual/master/#options-autofit-larger)
|
||||||
- [autofit-smaller](https://mpv.io/manual/master/#options-autofit-smaller)
|
Supported is a single integer value in the range 0-100.
|
||||||
- [autofit](https://mpv.io/manual/master/#options-autofit)
|
- [autofit-smaller](https://mpv.io/manual/master/#options-autofit-smaller)
|
||||||
|
Supported is a single integer value in the range 0-100.
|
||||||
|
- [autofit](https://mpv.io/manual/master/#options-autofit)
|
||||||
|
Supported is a single integer value in the range 0-100.
|
||||||
|
|
||||||
mpv.net specific window features are documented in the [screen section](#screen).
|
mpv.net specific window features are documented in the [screen section](#screen).
|
||||||
|
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ namespace mpvnet
|
|||||||
public bool KeepaspectWindow { get; set; }
|
public bool KeepaspectWindow { get; set; }
|
||||||
public bool Paused { get; set; }
|
public bool Paused { get; set; }
|
||||||
public bool Shown { get; set; }
|
public bool Shown { get; set; }
|
||||||
|
public bool SnapWindow { get; set; }
|
||||||
public bool TaskbarProgress { get; set; } = true;
|
public bool TaskbarProgress { get; set; } = true;
|
||||||
public bool WasInitialSizeSet;
|
public bool WasInitialSizeSet;
|
||||||
public bool WindowMaximized { get; set; }
|
public bool WindowMaximized { get; set; }
|
||||||
@@ -268,16 +269,17 @@ namespace mpvnet
|
|||||||
AutofitLarger = result / 100f;
|
AutofitLarger = result / 100f;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "border": Border = value == "yes"; break;
|
||||||
case "fs":
|
case "fs":
|
||||||
case "fullscreen": Fullscreen = value == "yes"; break;
|
case "fullscreen": Fullscreen = value == "yes"; break;
|
||||||
case "border": Border = value == "yes"; break;
|
case "gpu-api": GPUAPI = value; break;
|
||||||
case "keepaspect-window": KeepaspectWindow = value == "yes"; break;
|
case "keepaspect-window": KeepaspectWindow = value == "yes"; break;
|
||||||
|
case "screen": Screen = Convert.ToInt32(value); break;
|
||||||
|
case "snap-window": SnapWindow = value == "yes"; break;
|
||||||
|
case "taskbar-progress": TaskbarProgress = value == "yes"; 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 "taskbar-progress": TaskbarProgress = value == "yes"; break;
|
|
||||||
case "screen": Screen = Convert.ToInt32(value); break;
|
|
||||||
case "gpu-api": GPUAPI = value; break;
|
|
||||||
case "vo": VO = value; break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AutofitLarger > 1)
|
if (AutofitLarger > 1)
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ namespace mpvnet
|
|||||||
[DllImport("user32.dll")]
|
[DllImport("user32.dll")]
|
||||||
public static extern uint ActivateKeyboardLayout(IntPtr hkl, uint flags);
|
public static extern uint ActivateKeyboardLayout(IntPtr hkl, uint flags);
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
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(
|
||||||
IntPtr parentHandle, IntPtr childAfter, string lclassName, string windowTitle);
|
IntPtr parentHandle, IntPtr childAfter, string lclassName, string windowTitle);
|
||||||
@@ -88,6 +91,37 @@ namespace mpvnet
|
|||||||
[DllImport("gdi32.dll")]
|
[DllImport("gdi32.dll")]
|
||||||
public static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
|
public static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
|
||||||
|
|
||||||
|
[DllImport("dwmapi.dll")]
|
||||||
|
public static extern int DwmGetWindowAttribute(
|
||||||
|
IntPtr hwnd, uint dwAttribute, out RECT pvAttribute, uint cbAttribute);
|
||||||
|
|
||||||
|
public static bool GetDwmWindowRect(IntPtr handle, out RECT rect)
|
||||||
|
{
|
||||||
|
const uint DWMWA_EXTENDED_FRAME_BOUNDS = 9;
|
||||||
|
return 0 == DwmGetWindowAttribute(handle, DWMWA_EXTENDED_FRAME_BOUNDS, out rect, (uint)Marshal.SizeOf<RECT>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Rectangle GetWorkingArea(IntPtr handle, Rectangle workingArea)
|
||||||
|
{
|
||||||
|
if (handle != IntPtr.Zero && GetDwmWindowRect(handle, out RECT dwmRect) &&
|
||||||
|
GetWindowRect(handle, out RECT rect))
|
||||||
|
{
|
||||||
|
int left = workingArea.Left;
|
||||||
|
int top = workingArea.Top;
|
||||||
|
int right = workingArea.Right;
|
||||||
|
int bottom = workingArea.Bottom;
|
||||||
|
|
||||||
|
left += rect.Left - dwmRect.Left;
|
||||||
|
top -= rect.Top - dwmRect.Top;
|
||||||
|
right -= dwmRect.Right - rect.Right;
|
||||||
|
bottom -= dwmRect.Bottom - rect.Bottom;
|
||||||
|
|
||||||
|
return new Rectangle(left, top, right - left, bottom - top);
|
||||||
|
}
|
||||||
|
|
||||||
|
return workingArea;
|
||||||
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct RECT
|
public struct RECT
|
||||||
{
|
{
|
||||||
@@ -116,6 +150,16 @@ namespace mpvnet
|
|||||||
public Size Size => new Size(Right - Left, Bottom - Top);
|
public Size Size => new Size(Right - Left, Bottom - Top);
|
||||||
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)
|
||||||
|
{
|
||||||
|
return new RECT(rect.X, rect.Y, rect.X + rect.Width, rect.Y + rect.Height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return "{Left=" + Left + ",Top=" + Top + ",Right=" + Right + ",Bottom=" + Bottom + "}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
|||||||
@@ -459,12 +459,6 @@ help = keepaspect-window will lock the window size to the video aspect. Default:
|
|||||||
option = yes
|
option = yes
|
||||||
option = no
|
option = no
|
||||||
|
|
||||||
[setting]
|
|
||||||
name = start-threshold
|
|
||||||
file = mpvnet
|
|
||||||
filter = 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 specific option)
|
|
||||||
|
|
||||||
[setting]
|
[setting]
|
||||||
name = minimum-aspect-ratio
|
name = minimum-aspect-ratio
|
||||||
file = mpvnet
|
file = mpvnet
|
||||||
@@ -481,6 +475,16 @@ help = Save the window position on exit. (mpv.net specific option)
|
|||||||
option = yes
|
option = yes
|
||||||
option = no
|
option = no
|
||||||
|
|
||||||
|
[setting]
|
||||||
|
name = snap-window
|
||||||
|
file = mpv
|
||||||
|
default = no
|
||||||
|
filter = Screen
|
||||||
|
help = Snap the player window to screen edges.
|
||||||
|
|
||||||
|
option = yes
|
||||||
|
option = no
|
||||||
|
|
||||||
[setting]
|
[setting]
|
||||||
name = window-maximized
|
name = window-maximized
|
||||||
file = mpv
|
file = mpv
|
||||||
@@ -491,6 +495,12 @@ help = Start with a maximized window.
|
|||||||
option = yes
|
option = yes
|
||||||
option = no
|
option = no
|
||||||
|
|
||||||
|
[setting]
|
||||||
|
name = start-threshold
|
||||||
|
file = mpvnet
|
||||||
|
filter = 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 specific option)
|
||||||
|
|
||||||
[setting]
|
[setting]
|
||||||
name = taskbar-progress
|
name = taskbar-progress
|
||||||
file = mpv
|
file = mpv
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ namespace mpvnet
|
|||||||
{
|
{
|
||||||
public partial class MainForm : Form
|
public partial class MainForm : Form
|
||||||
{
|
{
|
||||||
|
public SnapManager SnapManager = new SnapManager();
|
||||||
public ElementHost CommandPaletteHost { get; set; }
|
public ElementHost CommandPaletteHost { get; set; }
|
||||||
public IntPtr mpvWindowHandle { get; set; }
|
public IntPtr mpvWindowHandle { get; set; }
|
||||||
public static MainForm Instance { get; set; }
|
public static MainForm Instance { get; set; }
|
||||||
@@ -221,7 +222,7 @@ namespace mpvnet
|
|||||||
if (FormBorderStyle == FormBorderStyle.None)
|
if (FormBorderStyle == FormBorderStyle.None)
|
||||||
top = ClientSize.Height * 0.1f;
|
top = ClientSize.Height * 0.1f;
|
||||||
|
|
||||||
return pos.Y > ClientSize.Height * 0.8 || pos.Y < top;
|
return pos.Y > ClientSize.Height * 0.78 || pos.Y < top;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateMenu()
|
void UpdateMenu()
|
||||||
@@ -432,13 +433,14 @@ namespace mpvnet
|
|||||||
}
|
}
|
||||||
|
|
||||||
Screen screen = Screen.FromControl(this);
|
Screen screen = Screen.FromControl(this);
|
||||||
int autoFitHeight = Convert.ToInt32(screen.WorkingArea.Height * Core.Autofit);
|
Rectangle workingArea = GetWorkingArea(Handle, screen.WorkingArea);
|
||||||
|
int autoFitHeight = Convert.ToInt32(workingArea.Height * Core.Autofit);
|
||||||
|
|
||||||
if (App.AutofitAudio > 1) App.AutofitAudio = 1;
|
if (App.AutofitAudio > 1) App.AutofitAudio = 1;
|
||||||
if (App.AutofitImage > 1) App.AutofitImage = 1;
|
if (App.AutofitImage > 1) App.AutofitImage = 1;
|
||||||
|
|
||||||
if (Core.IsAudio) autoFitHeight = Convert.ToInt32(screen.WorkingArea.Height * App.AutofitAudio);
|
if (Core.IsAudio) autoFitHeight = Convert.ToInt32(workingArea.Height * App.AutofitAudio);
|
||||||
if (Core.IsImage) autoFitHeight = Convert.ToInt32(screen.WorkingArea.Height * App.AutofitImage);
|
if (Core.IsImage) autoFitHeight = Convert.ToInt32(workingArea.Height * App.AutofitImage);
|
||||||
|
|
||||||
if (Core.VideoSize.Height == 0 || Core.VideoSize.Width == 0 ||
|
if (Core.VideoSize.Height == 0 || Core.VideoSize.Width == 0 ||
|
||||||
Core.VideoSize.Width / (float)Core.VideoSize.Height < App.MinimumAspectRatio)
|
Core.VideoSize.Width / (float)Core.VideoSize.Height < App.MinimumAspectRatio)
|
||||||
@@ -509,8 +511,10 @@ namespace mpvnet
|
|||||||
|
|
||||||
void SetSize(int width, int height, Screen screen, bool checkAutofit = true)
|
void SetSize(int width, int height, Screen screen, bool checkAutofit = true)
|
||||||
{
|
{
|
||||||
int maxHeight = screen.WorkingArea.Height - (Height - ClientSize.Height) - 2;
|
Rectangle workingArea = GetWorkingArea(Handle, screen.WorkingArea);
|
||||||
int maxWidth = screen.WorkingArea.Width - (Width - ClientSize.Width);
|
|
||||||
|
int maxHeight = workingArea.Height - (Height - ClientSize.Height) - 2;
|
||||||
|
int maxWidth = workingArea.Width - (Width - ClientSize.Width);
|
||||||
|
|
||||||
int startWidth = width;
|
int startWidth = width;
|
||||||
int startHeight = height;
|
int startHeight = height;
|
||||||
@@ -565,10 +569,10 @@ namespace mpvnet
|
|||||||
|
|
||||||
Screen[] screens = Screen.AllScreens;
|
Screen[] screens = Screen.AllScreens;
|
||||||
|
|
||||||
int minLeft = screens.Select(val => val.WorkingArea.X).Min();
|
int minLeft = screens.Select(val => GetWorkingArea(Handle, val.WorkingArea).X).Min();
|
||||||
int maxRight = screens.Select(val => val.WorkingArea.Right).Max();
|
int maxRight = screens.Select(val => GetWorkingArea(Handle, val.WorkingArea).Right).Max();
|
||||||
int minTop = screens.Select(val => val.WorkingArea.Y).Min();
|
int minTop = screens.Select(val => GetWorkingArea(Handle, val.WorkingArea).Y).Min();
|
||||||
int maxBottom = screens.Select(val => val.WorkingArea.Bottom).Max();
|
int maxBottom = screens.Select(val => GetWorkingArea(Handle, val.WorkingArea).Bottom).Max();
|
||||||
|
|
||||||
if (left < minLeft)
|
if (left < minLeft)
|
||||||
left = minLeft;
|
left = minLeft;
|
||||||
@@ -629,7 +633,7 @@ namespace mpvnet
|
|||||||
|
|
||||||
public int GetHorizontalLocation(Screen screen)
|
public int GetHorizontalLocation(Screen screen)
|
||||||
{
|
{
|
||||||
Rectangle workingArea = 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)
|
||||||
@@ -646,7 +650,7 @@ namespace mpvnet
|
|||||||
|
|
||||||
public int GetVerticalLocation(Screen screen)
|
public int GetVerticalLocation(Screen screen)
|
||||||
{
|
{
|
||||||
Rectangle workingArea = 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)
|
||||||
@@ -831,7 +835,7 @@ namespace mpvnet
|
|||||||
if (mpvWindowHandle != IntPtr.Zero)
|
if (mpvWindowHandle != IntPtr.Zero)
|
||||||
m.Result = SendMessage(mpvWindowHandle, m.Msg, m.WParam, m.LParam);
|
m.Result = SendMessage(mpvWindowHandle, m.Msg, m.WParam, m.LParam);
|
||||||
break;
|
break;
|
||||||
case 0x051: // WM_INPUTLANGCHANGE
|
case 0x51: // WM_INPUTLANGCHANGE
|
||||||
ActivateKeyboardLayout(m.LParam, 0x00000100u /*KLF_SETFORPROCESS*/);
|
ActivateKeyboardLayout(m.LParam, 0x00000100u /*KLF_SETFORPROCESS*/);
|
||||||
break;
|
break;
|
||||||
case 0x319: // WM_APPCOMMAND
|
case 0x319: // WM_APPCOMMAND
|
||||||
@@ -846,10 +850,10 @@ namespace mpvnet
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x0312: // WM_HOTKEY
|
case 0x312: // WM_HOTKEY
|
||||||
GlobalHotkey.Execute(m.WParam.ToInt32());
|
GlobalHotkey.Execute(m.WParam.ToInt32());
|
||||||
break;
|
break;
|
||||||
case 0x0200: // WM_MOUSEMOVE
|
case 0x200: // WM_MOUSEMOVE
|
||||||
if (Environment.TickCount - LastCycleFullscreen > 500)
|
if (Environment.TickCount - LastCycleFullscreen > 500)
|
||||||
{
|
{
|
||||||
Point pos = PointToClient(Cursor.Position);
|
Point pos = PointToClient(Cursor.Position);
|
||||||
@@ -869,7 +873,7 @@ namespace mpvnet
|
|||||||
Core.Command($"mouse {pos.X} {pos.Y} 0 double");
|
Core.Command($"mouse {pos.X} {pos.Y} 0 double");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x02E0: // WM_DPICHANGED
|
case 0x2E0: // WM_DPICHANGED
|
||||||
{
|
{
|
||||||
if (!Core.Shown)
|
if (!Core.Shown)
|
||||||
break;
|
break;
|
||||||
@@ -878,7 +882,7 @@ namespace mpvnet
|
|||||||
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 0x0214: // WM_SIZING
|
case 0x214: // WM_SIZING
|
||||||
if (Core.KeepaspectWindow)
|
if (Core.KeepaspectWindow)
|
||||||
{
|
{
|
||||||
RECT rc = Marshal.PtrToStructure<RECT>(m.LParam);
|
RECT rc = Marshal.PtrToStructure<RECT>(m.LParam);
|
||||||
@@ -906,7 +910,7 @@ namespace mpvnet
|
|||||||
m.Result = new IntPtr(1);
|
m.Result = new IntPtr(1);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case 0x004A: // WM_COPYDATA
|
case 0x4A: // WM_COPYDATA
|
||||||
{
|
{
|
||||||
var copyData = (COPYDATASTRUCT)m.GetLParam(typeof(COPYDATASTRUCT));
|
var copyData = (COPYDATASTRUCT)m.GetLParam(typeof(COPYDATASTRUCT));
|
||||||
string[] args = copyData.lpData.Split('\n');
|
string[] args = copyData.lpData.Split('\n');
|
||||||
@@ -990,6 +994,15 @@ namespace mpvnet
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 0x231: // WM_ENTERSIZEMOVE
|
||||||
|
case 0x005: // WM_SIZE
|
||||||
|
if (Core.SnapWindow)
|
||||||
|
SnapManager.OnSizeAndEnterSizeMove(this);
|
||||||
|
break;
|
||||||
|
case 0x216: // WM_MOVING
|
||||||
|
if (Core.SnapWindow)
|
||||||
|
SnapManager.OnMoving(ref m);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m.Msg == TaskbarButtonCreatedMessage && Core.TaskbarProgress)
|
if (m.Msg == TaskbarButtonCreatedMessage && Core.TaskbarProgress)
|
||||||
81
src/WinForms/SnapManager.cs
Normal file
81
src/WinForms/SnapManager.cs
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
using static mpvnet.Native;
|
||||||
|
|
||||||
|
namespace mpvnet
|
||||||
|
{
|
||||||
|
public class SnapManager
|
||||||
|
{
|
||||||
|
int DragOffsetX { get; set; }
|
||||||
|
int DragOffsetY { get; set; }
|
||||||
|
|
||||||
|
IntPtr Handle;
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum SnapLocation
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Left = 1 << 0,
|
||||||
|
Top = 1 << 1,
|
||||||
|
Right = 1 << 2,
|
||||||
|
Bottom = 1 << 3,
|
||||||
|
All = Left | Top | Right | Bottom
|
||||||
|
}
|
||||||
|
|
||||||
|
public int AnchorDistance { get; set; }
|
||||||
|
|
||||||
|
public int SnapDistance { get; set; }
|
||||||
|
|
||||||
|
bool InSnapRange(int a, int b) => Math.Abs(a - b) < SnapDistance;
|
||||||
|
|
||||||
|
void FindSnap(ref Rectangle effectiveBounds)
|
||||||
|
{
|
||||||
|
Screen currentScreen = Screen.FromPoint(effectiveBounds.Location);
|
||||||
|
Rectangle workingArea = GetWorkingArea(Handle, currentScreen.WorkingArea);
|
||||||
|
|
||||||
|
if (InSnapRange(effectiveBounds.Left, workingArea.Left + AnchorDistance))
|
||||||
|
effectiveBounds.X = workingArea.Left + AnchorDistance;
|
||||||
|
else if (InSnapRange(effectiveBounds.Right, workingArea.Right - AnchorDistance))
|
||||||
|
effectiveBounds.X = workingArea.Right - AnchorDistance - effectiveBounds.Width;
|
||||||
|
if (InSnapRange(effectiveBounds.Top, workingArea.Top + AnchorDistance))
|
||||||
|
effectiveBounds.Y = workingArea.Top + AnchorDistance;
|
||||||
|
else if (InSnapRange(effectiveBounds.Bottom, workingArea.Bottom - AnchorDistance))
|
||||||
|
effectiveBounds.Y = workingArea.Bottom - AnchorDistance - effectiveBounds.Height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnMoving(ref Message m)
|
||||||
|
{
|
||||||
|
if (Handle == IntPtr.Zero)
|
||||||
|
return;
|
||||||
|
|
||||||
|
RECT boundsLtrb = Marshal.PtrToStructure<RECT>(m.LParam);
|
||||||
|
Rectangle bounds = boundsLtrb.ToRectangle();
|
||||||
|
// This is where the window _would_ be located if snapping
|
||||||
|
// had not occurred. This prevents the cursor from sliding
|
||||||
|
// off the title bar if the snap distance is too large.
|
||||||
|
Rectangle effectiveBounds = new Rectangle(
|
||||||
|
Cursor.Position.X - DragOffsetX,
|
||||||
|
Cursor.Position.Y - DragOffsetY,
|
||||||
|
bounds.Width,
|
||||||
|
bounds.Height);
|
||||||
|
FindSnap(ref effectiveBounds);
|
||||||
|
RECT newLtrb = RECT.FromRectangle(effectiveBounds);
|
||||||
|
Marshal.StructureToPtr(newLtrb, m.LParam, false);
|
||||||
|
m.Result = new IntPtr(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnSizeAndEnterSizeMove(Form form)
|
||||||
|
{
|
||||||
|
Handle = form.Handle;
|
||||||
|
SnapDistance = form.Font.Height;
|
||||||
|
// Need to handle window size changed as well when
|
||||||
|
// un-maximizing the form by dragging the title bar.
|
||||||
|
DragOffsetX = Cursor.Position.X - form.Left;
|
||||||
|
DragOffsetY = Cursor.Position.Y - form.Top;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -93,6 +93,7 @@
|
|||||||
<Compile Include="Misc\Common.cs" />
|
<Compile Include="Misc\Common.cs" />
|
||||||
<Compile Include="Misc\FolderBrowser.cs" />
|
<Compile Include="Misc\FolderBrowser.cs" />
|
||||||
<Compile Include="Misc\JSONParser.cs" />
|
<Compile Include="Misc\JSONParser.cs" />
|
||||||
|
<Compile Include="WinForms\SnapManager.cs" />
|
||||||
<Compile Include="WPF\HandyControl\Controls\Attach\BorderElement.cs" />
|
<Compile Include="WPF\HandyControl\Controls\Attach\BorderElement.cs" />
|
||||||
<Compile Include="WPF\HandyControl\Controls\Attach\MenuTopLineAttach.cs" />
|
<Compile Include="WPF\HandyControl\Controls\Attach\MenuTopLineAttach.cs" />
|
||||||
<Compile Include="WPF\HandyControl\Tools\Converter\BorderCircularConverter.cs" />
|
<Compile Include="WPF\HandyControl\Tools\Converter\BorderCircularConverter.cs" />
|
||||||
@@ -186,10 +187,10 @@
|
|||||||
<DependentUpon>Resources.resx</DependentUpon>
|
<DependentUpon>Resources.resx</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Native\libmpv.cs" />
|
<Compile Include="Native\libmpv.cs" />
|
||||||
<Compile Include="Misc\MainForm.cs">
|
<Compile Include="WinForms\MainForm.cs">
|
||||||
<SubType>Form</SubType>
|
<SubType>Form</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Misc\MainForm.Designer.cs">
|
<Compile Include="WinForms\MainForm.Designer.cs">
|
||||||
<DependentUpon>MainForm.cs</DependentUpon>
|
<DependentUpon>MainForm.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Misc\Misc.cs" />
|
<Compile Include="Misc\Misc.cs" />
|
||||||
@@ -211,7 +212,7 @@
|
|||||||
<DependentUpon>InputWindow.xaml</DependentUpon>
|
<DependentUpon>InputWindow.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="WPF\WPF.cs" />
|
<Compile Include="WPF\WPF.cs" />
|
||||||
<EmbeddedResource Include="Misc\MainForm.resx">
|
<EmbeddedResource Include="WinForms\MainForm.resx">
|
||||||
<DependentUpon>MainForm.cs</DependentUpon>
|
<DependentUpon>MainForm.cs</DependentUpon>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
|
|||||||
Reference in New Issue
Block a user