[update] 用上了lindexi的稳定全屏化方案,为白板右上角鸡汤添加了自定义选项,优化部分代码,给QuickPanel加上了Easing

This commit is contained in:
Dubi906w 2024-06-07 21:27:16 +08:00
parent f5ee4ef00a
commit e10d71787e
11 changed files with 1060 additions and 101 deletions

View File

@ -0,0 +1,375 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
// 由衷感謝 lindexi 提供的 《WPF 稳定的全屏化窗口方法》
// 文章鏈接https://blog.lindexi.com/post/WPF-%E7%A8%B3%E5%AE%9A%E7%9A%84%E5%85%A8%E5%B1%8F%E5%8C%96%E7%AA%97%E5%8F%A3%E6%96%B9%E6%B3%95.html
// lindexi 的部落格https://blog.lindexi.com/
namespace Ink_Canvas.Helpers
{
public static partial class FullScreenHelper
{
static class Win32
{
[Flags]
public enum ShowWindowCommands
{
/// <summary>
/// Maximizes the specified window.
/// </summary>
SW_MAXIMIZE = 3,
/// <summary>
/// Activates and displays the window. If the window is minimized or maximized, the system restores it to its original
/// size and position. An application should specify this flag when restoring a minimized window.
/// </summary>
SW_RESTORE = 9,
}
internal static class Properties
{
#if !ANSI
public const CharSet BuildCharSet = CharSet.Unicode;
#else
public const CharSet BuildCharSet = CharSet.Ansi;
#endif
}
public static class Dwmapi
{
public const string LibraryName = "Dwmapi.dll";
[DllImport(LibraryName, ExactSpelling = true, PreserveSig = false)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DwmIsCompositionEnabled();
[DllImport("Dwmapi.dll", ExactSpelling = true, SetLastError = true)]
public static extern int DwmSetWindowAttribute(IntPtr hwnd, DWMWINDOWATTRIBUTE dwAttribute,
in int pvAttribute, uint cbAttribute);
}
public static class User32
{
public const string LibraryName = "user32";
[DllImport(LibraryName, CharSet = Properties.BuildCharSet)]
public static extern bool GetMonitorInfo(IntPtr hMonitor, ref MonitorInfo lpmi);
[DllImport(LibraryName, ExactSpelling = true)]
public static extern IntPtr MonitorFromRect(in Rectangle lprc, MonitorFlag dwFlags);
[DllImport(LibraryName, ExactSpelling = true)]
public static extern bool IsIconic(IntPtr hwnd);
[DllImport(LibraryName, ExactSpelling = true)]
public static extern bool ShowWindow(IntPtr hWnd, ShowWindowCommands nCmdShow);
[DllImport(LibraryName, ExactSpelling = true)]
public static extern bool SetWindowPlacement(IntPtr hWnd,
[In] ref WINDOWPLACEMENT lpwndpl);
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport(LibraryName, ExactSpelling = true)]
public static extern bool GetWindowRect(IntPtr hWnd, out Rectangle lpRect);
[DllImport(LibraryName, ExactSpelling = true, SetLastError = true)]
public static extern Int32 SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, Int32 x, Int32 y, Int32 cx,
Int32 cy, Int32 wFlagslong);
[DllImport(LibraryName, ExactSpelling = true)]
public static extern bool GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
public static IntPtr GetWindowLongPtr(IntPtr hWnd, GetWindowLongFields nIndex) =>
GetWindowLongPtr(hWnd, (int) nIndex);
public static IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex)
{
return IntPtr.Size > 4
#pragma warning disable CS0618 // 类型或成员已过时
? GetWindowLongPtr_x64(hWnd, nIndex)
: new IntPtr(GetWindowLong(hWnd, nIndex));
#pragma warning restore CS0618 // 类型或成员已过时
}
[DllImport(LibraryName, CharSet = Properties.BuildCharSet)]
public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport(LibraryName, CharSet = Properties.BuildCharSet, EntryPoint = "GetWindowLongPtr")]
public static extern IntPtr GetWindowLongPtr_x64(IntPtr hWnd, int nIndex);
public static IntPtr SetWindowLongPtr(IntPtr hWnd, GetWindowLongFields nIndex, IntPtr dwNewLong) =>
SetWindowLongPtr(hWnd, (int) nIndex, dwNewLong);
public static IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong)
{
return IntPtr.Size > 4
#pragma warning disable CS0618 // 类型或成员已过时
? SetWindowLongPtr_x64(hWnd, nIndex, dwNewLong)
: new IntPtr(SetWindowLong(hWnd, nIndex, dwNewLong.ToInt32()));
#pragma warning restore CS0618 // 类型或成员已过时
}
[DllImport(LibraryName, CharSet = Properties.BuildCharSet, EntryPoint = "SetWindowLongPtr")]
public static extern IntPtr SetWindowLongPtr_x64(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
[DllImport(LibraryName, CharSet = Properties.BuildCharSet)]
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
}
}
[StructLayout(LayoutKind.Sequential)]
struct MonitorInfo
{
/// <summary>
/// The size of the structure, in bytes.
/// </summary>
public uint Size;
/// <summary>
/// A RECT structure that specifies the display monitor rectangle, expressed in virtual-screen coordinates. Note that
/// if the monitor is not the primary display monitor, some of the rectangle's coordinates may be negative values.
/// </summary>
public Rectangle MonitorRect;
/// <summary>
/// A RECT structure that specifies the work area rectangle of the display monitor, expressed in virtual-screen
/// coordinates. Note that if the monitor is not the primary display monitor, some of the rectangle's coordinates may
/// be negative values.
/// </summary>
public Rectangle WorkRect;
/// <summary>
/// A set of flags that represent attributes of the display monitor.
/// </summary>
public MonitorInfoFlag Flags;
}
enum MonitorInfoFlag
{
}
enum MonitorFlag
{
/// <summary>
/// Returns a handle to the primary display monitor.
/// </summary>
MONITOR_DEFAULTTOPRIMARY = 1,
}
[StructLayout(LayoutKind.Sequential)]
struct WindowPosition
{
public IntPtr Hwnd;
public IntPtr HwndZOrderInsertAfter;
public int X;
public int Y;
public int Width;
public int Height;
public WindowPositionFlags Flags;
}
enum HwndZOrder
{
/// <summary>
/// Places the window at the top of the Z order.
/// </summary>
HWND_TOP = 0,
}
enum DWMWINDOWATTRIBUTE : uint
{
DWMWA_TRANSITIONS_FORCEDISABLED = 3,
}
enum GetWindowLongFields
{
/// <summary>
/// 设定一个新的窗口风格
/// Retrieves the window styles
/// </summary>
GWL_STYLE = -16,
}
[StructLayout(LayoutKind.Sequential)]
struct WINDOWPLACEMENT // WindowPlacement
{
public uint Size;
public WindowPlacementFlags Flags;
public Win32.ShowWindowCommands ShowCmd;
public Point MinPosition;
public Point MaxPosition;
public Rectangle NormalPosition;
}
[Flags]
public enum WindowPositionFlags
{
/// <summary>
/// <para>
/// 清除客户区的所有内容。如果未设置该标志,客户区的有效内容被保存并且在窗口尺寸更新和重定位后拷贝回客户区
/// </para>
/// Discards the entire contents of the client area. If this flag is not specified, the valid contents of the client
/// area are saved and copied back into the client area after the window is sized or repositioned.
/// </summary>
SWP_NOCOPYBITS = 0x0100,
/// <summary>
/// <para>
/// 维持当前位置忽略X和Y参数
/// </para>
/// Retains the current position (ignores X and Y parameters).
/// </summary>
SWP_NOMOVE = 0x0002,
/// <summary>
/// <para>
/// 不重画改变的内容。如果设置了这个标志,则不发生任何重画动作。适用于客户区和非客户区(包括标题栏和滚动条)和任何由于窗回移动而露出的父窗口的所有部分。如果设置了这个标志,应用程序必须明确地使窗口无效并区重画窗口的任何部分和父窗口需要重画的部分
/// </para>
/// Does not redraw changes. If this flag is set, no repainting of any kind occurs. This applies to the client area,
/// the nonclient area (including the title bar and scroll bars), and any part of the parent window uncovered as a
/// result of the window being moved. When this flag is set, the application must explicitly invalidate or redraw any
/// parts of the window and parent window that need redrawing.
/// </summary>
SWP_NOREDRAW = 0x0008,
/// <summary>
/// <para>
/// 维持当前尺寸(忽略 cx 和 cy 参数)
/// </para>
/// Retains the current size (ignores the cx and cy parameters).
/// </summary>
SWP_NOSIZE = 0x0001,
/// <summary>
/// <para>
/// 维持当前 Z 序(忽略 hWndlnsertAfter 参数)
/// </para>
/// Retains the current Z order (ignores the hWndInsertAfter parameter).
/// </summary>
SWP_NOZORDER = 0x0004,
}
[StructLayout(LayoutKind.Sequential)]
struct Rectangle
{
public int Left;
public int Top;
public int Right;
public int Bottom;
/// <summary>
/// 矩形的宽度
/// </summary>
public int Width
{
get { return unchecked((int) (Right - Left)); }
set { Right = unchecked((int) (Left + value)); }
}
/// <summary>
/// 矩形的高度
/// </summary>
public int Height
{
get { return unchecked((int) (Bottom - Top)); }
set { Bottom = unchecked((int) (Top + value)); }
}
public bool Equals(Rectangle other)
{
return (Left == other.Left) && (Right == other.Right) && (Top == other.Top) && (Bottom == other.Bottom);
}
public override bool Equals(object obj)
{
return obj is Rectangle rectangle && Equals(rectangle);
}
public static bool operator ==(Rectangle left, Rectangle right)
{
return left.Equals(right);
}
public override int GetHashCode()
{
unchecked
{
var hashCode = (int) Left;
hashCode = (hashCode * 397) ^ (int) Top;
hashCode = (hashCode * 397) ^ (int) Right;
hashCode = (hashCode * 397) ^ (int) Bottom;
return hashCode;
}
}
public static bool operator !=(Rectangle left, Rectangle right)
{
return !(left == right);
}
}
[StructLayout(LayoutKind.Sequential)]
struct Point
{
public int X;
public int Y;
}
[Flags]
enum WindowPlacementFlags
{
}
[Flags]
enum WindowStyles
{
/// <summary>
/// The window is initially maximized.
/// </summary>
WS_MAXIMIZE = 0x01000000,
/// <summary>
/// The window has a maximize button. Cannot be combined with the WS_EX_CONTEXTHELP style. The WS_SYSMENU style must
/// also be specified.
/// </summary>
WS_MAXIMIZEBOX = 0x00010000,
/// <summary>
/// The window is initially minimized. Same as the WS_ICONIC style.
/// </summary>
WS_MINIMIZE = 0x20000000,
/// <summary>
/// The window has a sizing border. Same as the WS_SIZEBOX style.
/// </summary>
WS_THICKFRAME = 0x00040000,
}
[ComImport]
[Guid("602D4995-B13A-429b-A66E-1935E44F4317")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface ITaskbarList2
{
[PreserveSig]
int HrInit();
[PreserveSig]
int AddTab(IntPtr hwnd);
[PreserveSig]
int DeleteTab(IntPtr hwnd);
[PreserveSig]
int ActivateTab(IntPtr hwnd);
[PreserveSig]
int SetActiveAlt(IntPtr hwnd);
[PreserveSig]
int MarkFullscreenWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.Bool)] bool fFullscreen);
}
}
}

View File

@ -0,0 +1,301 @@
using System;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
// 由衷感謝 lindexi 提供的 《WPF 稳定的全屏化窗口方法》
// 文章鏈接https://blog.lindexi.com/post/WPF-%E7%A8%B3%E5%AE%9A%E7%9A%84%E5%85%A8%E5%B1%8F%E5%8C%96%E7%AA%97%E5%8F%A3%E6%96%B9%E6%B3%95.html
// lindexi 的部落格https://blog.lindexi.com/
namespace Ink_Canvas.Helpers
{
/// <summary>
/// 用来使窗口变得全屏的辅助类
/// 采用设置窗口位置和尺寸,确保盖住整个屏幕的方式来实现全屏
/// 目前已知需要满足的条件是窗口盖住整个屏幕、窗口没有WS_THICKFRAME样式、窗口不能有标题栏且最大化
/// </summary>
public static partial class FullScreenHelper
{
public static void MarkFullscreenWindowTaskbarList(IntPtr hwnd, bool isFullscreen)
{
try
{
var CLSID_TaskbarList = new Guid("56FDF344-FD6D-11D0-958A-006097C9A090");
var obj = Activator.CreateInstance(Type.GetTypeFromCLSID(CLSID_TaskbarList));
(obj as ITaskbarList2)?.MarkFullscreenWindow(hwnd, isFullscreen);
}
catch
{
//应该不会挂
}
}
/// <summary>
/// 用于记录窗口全屏前位置的附加属性
/// </summary>
private static readonly DependencyProperty BeforeFullScreenWindowPlacementProperty =
DependencyProperty.RegisterAttached("BeforeFullScreenWindowPlacement", typeof(WINDOWPLACEMENT?),
typeof(Window));
/// <summary>
/// 用于记录窗口全屏前样式的附加属性
/// </summary>
private static readonly DependencyProperty BeforeFullScreenWindowStyleProperty =
DependencyProperty.RegisterAttached("BeforeFullScreenWindowStyle", typeof(WindowStyles?), typeof(Window));
/// <summary>
/// 开始进入全屏模式
/// 进入全屏模式后,窗口可通过 API 方式(也可以用 Win + Shift + Left/Right移动调整大小但会根据目标矩形寻找显示器重新调整到全屏状态。
/// 进入全屏后,不要修改样式等窗口属性,在退出时,会恢复到进入前的状态
/// 进入全屏模式后会禁用 DWM 过渡动画
/// </summary>
/// <param name="window"></param>
public static void StartFullScreen(Window window)
{
if (window == null)
{
throw new ArgumentNullException(nameof(window), $"{nameof(window)} 不能为 null");
}
//确保不在全屏模式
if (window.GetValue(BeforeFullScreenWindowPlacementProperty) == null &&
window.GetValue(BeforeFullScreenWindowStyleProperty) == null)
{
var hwnd = new WindowInteropHelper(window).EnsureHandle();
var hwndSource = HwndSource.FromHwnd(hwnd);
//获取当前窗口的位置大小状态并保存
var placement = new WINDOWPLACEMENT();
placement.Size = (uint) Marshal.SizeOf(placement);
Win32.User32.GetWindowPlacement(hwnd, ref placement);
window.SetValue(BeforeFullScreenWindowPlacementProperty, placement);
//修改窗口样式
var style = (WindowStyles) Win32.User32.GetWindowLongPtr(hwnd, GetWindowLongFields.GWL_STYLE);
window.SetValue(BeforeFullScreenWindowStyleProperty, style);
//将窗口恢复到还原模式,在有标题栏的情况下最大化模式下无法全屏,
//这里采用还原,不修改标题栏的方式
//在退出全屏时,窗口原有的状态会恢复
//去掉WS_THICKFRAME在有该样式的情况下不能全屏
//去掉WS_MAXIMIZEBOX禁用最大化如果最大化会退出全屏
//去掉WS_MAXIMIZE使窗口变成还原状态不使用ShowWindow(hwnd, ShowWindowCommands.SW_RESTORE)避免看到窗口变成还原状态这一过程也避免影响窗口的Visible状态
style &= (~(WindowStyles.WS_THICKFRAME | WindowStyles.WS_MAXIMIZEBOX | WindowStyles.WS_MAXIMIZE));
Win32.User32.SetWindowLongPtr(hwnd, GetWindowLongFields.GWL_STYLE, (IntPtr) style);
//禁用 DWM 过渡动画 忽略返回值若DWM关闭不做处理
Win32.Dwmapi.DwmSetWindowAttribute(hwnd, DWMWINDOWATTRIBUTE.DWMWA_TRANSITIONS_FORCEDISABLED, 1,
sizeof(int));
//添加Hook在窗口尺寸位置等要发生变化时确保全屏
hwndSource.AddHook(KeepFullScreenHook);
if (Win32.User32.GetWindowRect(hwnd, out var rect))
{
//不能用 placement 的坐标placement是工作区坐标不是屏幕坐标。
//使用窗口当前的矩形调用下设置窗口位置和尺寸的方法让Hook来进行调整窗口位置和尺寸到全屏模式
Win32.User32.SetWindowPos(hwnd, (IntPtr) HwndZOrder.HWND_TOP, rect.Left, rect.Top, rect.Width,
rect.Height, (int) WindowPositionFlags.SWP_NOZORDER);
}
}
}
/// <summary>
/// 退出全屏模式
/// 窗口会回到进入全屏模式时保存的状态
/// 退出全屏模式后会重新启用 DWM 过渡动画
/// </summary>
/// <param name="window"></param>
public static void EndFullScreen(Window window)
{
if (window == null)
{
throw new ArgumentNullException(nameof(window), $"{nameof(window)} 不能为 null");
}
//确保在全屏模式并获取之前保存的状态
if (window.GetValue(BeforeFullScreenWindowPlacementProperty) is WINDOWPLACEMENT placement
&& window.GetValue(BeforeFullScreenWindowStyleProperty) is WindowStyles style)
{
var hwnd = new WindowInteropHelper(window).Handle;
if (hwnd == IntPtr.Zero)
{
// 句柄为 0 只有两种情况:
// 1. 虽然窗口已进入全屏,但窗口已被关闭;
// 2. 窗口初始化前,在还没有调用 StartFullScreen 的前提下就调用了此方法。
// 所以,直接 return 就好。
return;
}
var hwndSource = HwndSource.FromHwnd(hwnd);
//去除hook
hwndSource.RemoveHook(KeepFullScreenHook);
//恢复保存的状态
//不要改变Style里的WS_MAXIMIZE否则会使窗口变成最大化状态但是尺寸不对
//也不要设置回Style里的WS_MINIMIZE,否则会导致窗口最小化按钮显示成还原按钮
Win32.User32.SetWindowLongPtr(hwnd, GetWindowLongFields.GWL_STYLE,
(IntPtr) (style & (~(WindowStyles.WS_MAXIMIZE | WindowStyles.WS_MINIMIZE))));
if ((style & WindowStyles.WS_MINIMIZE) != 0)
{
//如果窗口进入全屏前是最小化的,这里不让窗口恢复到之前的最小化状态,而是到还原的状态。
//大多数情况下,都不期望在退出全屏的时候,恢复到最小化。
placement.ShowCmd = Win32.ShowWindowCommands.SW_RESTORE;
}
if ((style & WindowStyles.WS_MAXIMIZE) != 0)
{
//提前调用 ShowWindow 使窗口恢复最大化,若通过 SetWindowPlacement 最大化会导致闪烁,只靠其恢复 RestoreBounds.
Win32.User32.ShowWindow(hwnd, Win32.ShowWindowCommands.SW_MAXIMIZE);
}
Win32.User32.SetWindowPlacement(hwnd, ref placement);
if ((style & WindowStyles.WS_MAXIMIZE) ==
0) //如果窗口是最大化就不要修改WPF属性否则会破坏RestoreBounds且WPF窗口自身在最大化时不会修改 Left Top Width Height 属性
{
if (Win32.User32.GetWindowRect(hwnd, out var rect))
{
//不能用 placement 的坐标placement是工作区坐标不是屏幕坐标。
//确保窗口的 WPF 属性与 Win32 位置一致
var logicalPos =
hwndSource.CompositionTarget.TransformFromDevice.Transform(
new System.Windows.Point(rect.Left, rect.Top));
var logicalSize =
hwndSource.CompositionTarget.TransformFromDevice.Transform(
new System.Windows.Point(rect.Width, rect.Height));
window.Left = logicalPos.X;
window.Top = logicalPos.Y;
window.Width = logicalSize.X;
window.Height = logicalSize.Y;
}
}
//重新启用 DWM 过渡动画 忽略返回值若DWM关闭不做处理
Win32.Dwmapi.DwmSetWindowAttribute(hwnd, DWMWINDOWATTRIBUTE.DWMWA_TRANSITIONS_FORCEDISABLED, 0,
sizeof(int));
//删除保存的状态
window.ClearValue(BeforeFullScreenWindowPlacementProperty);
window.ClearValue(BeforeFullScreenWindowStyleProperty);
}
}
/// <summary>
/// 确保窗口全屏的Hook
/// 使用HandleProcessCorruptedStateExceptions防止访问内存过程中因为一些致命异常导致程序崩溃
/// </summary>
[HandleProcessCorruptedStateExceptions]
private static IntPtr KeepFullScreenHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
//处理WM_WINDOWPOSCHANGING消息
const int WINDOWPOSCHANGING = 0x0046;
if (msg == WINDOWPOSCHANGING)
{
try
{
//得到WINDOWPOS结构体
var pos = (WindowPosition) Marshal.PtrToStructure(lParam, typeof(WindowPosition));
if ((pos.Flags & WindowPositionFlags.SWP_NOMOVE) != 0 &&
(pos.Flags & WindowPositionFlags.SWP_NOSIZE) != 0)
{
//既然你既不改变位置,也不改变尺寸,我就不管了...
return IntPtr.Zero;
}
if (Win32.User32.IsIconic(hwnd))
{
// 如果在全屏期间最小化了窗口,那么忽略后续的位置调整。
// 否则按后续逻辑,会根据窗口在 -32000 的位置,计算出错误的目标位置,然后就跳到主屏了。
return IntPtr.Zero;
}
//获取窗口现在的矩形,下面用来参考计算目标矩形
if (Win32.User32.GetWindowRect(hwnd, out var rect))
{
var targetRect = rect; //窗口想要变化的目标矩形
if ((pos.Flags & WindowPositionFlags.SWP_NOMOVE) == 0)
{
//需要移动
targetRect.Left = pos.X;
targetRect.Top = pos.Y;
}
if ((pos.Flags & WindowPositionFlags.SWP_NOSIZE) == 0)
{
//要改变尺寸
targetRect.Right = targetRect.Left + pos.Width;
targetRect.Bottom = targetRect.Top + pos.Height;
}
else
{
//不改变尺寸
targetRect.Right = targetRect.Left + rect.Width;
targetRect.Bottom = targetRect.Top + rect.Height;
}
//使用目标矩形获取显示器信息
var monitor = Win32.User32.MonitorFromRect(targetRect, MonitorFlag.MONITOR_DEFAULTTOPRIMARY);
var info = new MonitorInfo();
info.Size = (uint) Marshal.SizeOf(info);
if (Win32.User32.GetMonitorInfo(monitor, ref info))
{
//基于显示器信息设置窗口尺寸位置
pos.X = info.MonitorRect.Left;
pos.Y = info.MonitorRect.Top;
pos.Width = info.MonitorRect.Right - info.MonitorRect.Left;
pos.Height = info.MonitorRect.Bottom - info.MonitorRect.Top;
pos.Flags &= ~(WindowPositionFlags.SWP_NOSIZE | WindowPositionFlags.SWP_NOMOVE |
WindowPositionFlags.SWP_NOREDRAW);
pos.Flags |= WindowPositionFlags.SWP_NOCOPYBITS;
if (rect == info.MonitorRect)
{
var hwndSource = HwndSource.FromHwnd(hwnd);
if (hwndSource?.RootVisual is Window window)
{
//确保窗口的 WPF 属性与 Win32 位置一致,防止有逗比全屏后改 WPF 的属性,发生一些诡异的行为
//下面这样做其实不太好,会再次触发 WM_WINDOWPOSCHANGING 来着.....但是又没有其他时机了
// WM_WINDOWPOSCHANGED 不能用
//(例如:在进入全屏后,修改 Left 属性,会进入 WM_WINDOWPOSCHANGING然后在这里将消息里的结构体中的 Left 改回,
// 使对 Left 的修改无效,那么将不会进入 WM_WINDOWPOSCHANGED窗口尺寸正常但窗口的 Left 属性值错误。)
var logicalPos =
hwndSource.CompositionTarget.TransformFromDevice.Transform(
new System.Windows.Point(pos.X, pos.Y));
var logicalSize =
hwndSource.CompositionTarget.TransformFromDevice.Transform(
new System.Windows.Point(pos.Width, pos.Height));
window.Left = logicalPos.X;
window.Top = logicalPos.Y;
window.Width = logicalSize.X;
window.Height = logicalSize.Y;
}
else
{
//这个hwnd是前面从Window来的如果现在他不是Window...... 你信么
}
}
//将修改后的结构体拷贝回去
Marshal.StructureToPtr(pos, lParam, false);
}
}
}
catch
{
// 这里也不需要日志啥的,只是为了防止上面有逗比逻辑,在消息循环里面炸了
}
}
return IntPtr.Zero;
}
}
}

View File

@ -493,6 +493,33 @@
<!-- <!--
<ui:ToggleSwitch OnContent="" OffContent="" Header="显示“橡皮”按钮" IsOn="{Binding ElementName=ToggleSwitchShowButtonEraser, Path=IsOn}" FontFamily="Microsoft YaHei UI"/> <ui:ToggleSwitch OnContent="" OffContent="" Header="显示“橡皮”按钮" IsOn="{Binding ElementName=ToggleSwitchShowButtonEraser, Path=IsOn}" FontFamily="Microsoft YaHei UI"/>
--> -->
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<TextBlock Foreground="#fafafa" Text="浮动工具栏缩放" VerticalAlignment="Center"
FontSize="14" Margin="0,0,16,0" />
<Slider x:Name="ViewboxFloatingBarScaleTransformValueSlider" Minimum="0.5"
Maximum="1.25" Width="168" FontFamily="Microsoft YaHei UI"
FontSize="20" IsSnapToTickEnabled="True" Value="1" TickFrequency="0.05"
TickPlacement="None" AutoToolTipPlacement="None"
ValueChanged="ViewboxFloatingBarScaleTransformValueSlider_ValueChanged" />
<TextBlock
Text="{Binding ElementName=ViewboxFloatingBarScaleTransformValueSlider, Path=Value}"
VerticalAlignment="Center" FontSize="14" FontFamily="Consolas"
Margin="12,0,16,0" />
</ui:SimpleStackPanel>
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<TextBlock Foreground="#fafafa" Text="浮动工具栏透明度" VerticalAlignment="Center"
FontSize="14" Margin="0,0,16,0" />
<Slider x:Name="ViewboxFloatingBarOpacityValueSlider" Minimum="0.3"
Maximum="1" Width="168" FontFamily="Microsoft YaHei UI"
FontSize="20" IsSnapToTickEnabled="True" Value="1" TickFrequency="0.05"
TickPlacement="None" AutoToolTipPlacement="None"/>
<TextBlock
Text="{Binding ElementName=ViewboxFloatingBarOpacityValueSlider, Path=Value}"
VerticalAlignment="Center" FontSize="14" FontFamily="Consolas"
Margin="12,0,16,0" />
</ui:SimpleStackPanel>
<Line HorizontalAlignment="Center" X1="0" Y1="0" X2="400" Y2="0"
Stroke="#3f3f46" StrokeThickness="1" Margin="0,4,0,4" />
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left"> <ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<TextBlock Foreground="#fafafa" Text="在调色盘窗口中显示 笔尖模式 按钮" <TextBlock Foreground="#fafafa" Text="在调色盘窗口中显示 笔尖模式 按钮"
VerticalAlignment="Center" FontSize="14" Margin="0,0,16,0" /> VerticalAlignment="Center" FontSize="14" Margin="0,0,16,0" />
@ -501,23 +528,13 @@
FontFamily="Microsoft YaHei UI" FontWeight="Bold" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
Toggled="ToggleSwitchEnableDisPlayNibModeToggle_Toggled" /> Toggled="ToggleSwitchEnableDisPlayNibModeToggle_Toggled" />
</ui:SimpleStackPanel> </ui:SimpleStackPanel>
<Line HorizontalAlignment="Center" X1="0" Y1="0" X2="400" Y2="0"
Stroke="#3f3f46" StrokeThickness="1" Margin="0,4,0,4" />
<!--<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left"> <!--<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<TextBlock Text="浮动工具栏背景色" VerticalAlignment="Center" FontSize="14" Margin="0,0,16,0"/> <TextBlock Text="浮动工具栏背景色" VerticalAlignment="Center" FontSize="14" Margin="0,0,16,0"/>
<ui:ToggleSwitch OnContent="" OffContent="" Name="ToggleSwitchColorfulViewboxFloatingBar" IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold" Toggled="ToggleSwitchIsColorfulViewboxFloatingBar_Toggled" /> <ui:ToggleSwitch OnContent="" OffContent="" Name="ToggleSwitchColorfulViewboxFloatingBar" IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold" Toggled="ToggleSwitchIsColorfulViewboxFloatingBar_Toggled" />
</ui:SimpleStackPanel>--> </ui:SimpleStackPanel>-->
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<TextBlock Foreground="#fafafa" Text="浮动工具栏缩放" VerticalAlignment="Center"
FontSize="14" Margin="0,0,16,0" />
<Slider x:Name="ViewboxFloatingBarScaleTransformValueSlider" Minimum="0.5"
Maximum="1.25" Width="168" FontFamily="Microsoft YaHei UI"
FontSize="20" IsSnapToTickEnabled="True" Value="1" TickFrequency="0.05"
TickPlacement="None"
ValueChanged="ViewboxFloatingBarScaleTransformValueSlider_ValueChanged" />
<TextBlock
Text="{Binding ElementName=ViewboxFloatingBarScaleTransformValueSlider, Path=Value}"
VerticalAlignment="Center" FontSize="14" FontFamily="Consolas"
Margin="12,0,16,0" />
</ui:SimpleStackPanel>
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left"> <ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<TextBlock Foreground="#fafafa" Text="白板 UI 80% 缩放" VerticalAlignment="Center" <TextBlock Foreground="#fafafa" Text="白板 UI 80% 缩放" VerticalAlignment="Center"
FontSize="14" Margin="0,0,16,0" /> FontSize="14" Margin="0,0,16,0" />
@ -534,6 +551,26 @@
IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold" IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
Toggled="ToggleSwitchEnableTimeDisplayInWhiteboardMode_Toggled" /> Toggled="ToggleSwitchEnableTimeDisplayInWhiteboardMode_Toggled" />
</ui:SimpleStackPanel> </ui:SimpleStackPanel>
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<TextBlock Foreground="#fafafa" Text="在白板中显示信仰の源(好喝的/毒的鸡汤)" VerticalAlignment="Center"
FontSize="14" Margin="0,0,16,0" />
<ui:ToggleSwitch OnContent="" OffContent=""
Name="ToggleSwitchEnableChickenSoupInWhiteboardMode"
IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
Toggled="ToggleSwitchEnableChickenSoupInWhiteboardMode_Toggled"/>
</ui:SimpleStackPanel>
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<TextBlock Foreground="#fafafa" Text="信仰の源出自Where" VerticalAlignment="Center"
FontSize="14" Margin="0,0,16,0" />
<ComboBox Name="ComboBoxChickenSoupSource" FontFamily="Microsoft YaHei UI"
SelectedIndex="1" SelectionChanged="ComboBoxChickenSoupSource_SelectionChanged">
<ComboBoxItem Content="osu!玩家语录" FontFamily="Microsoft YaHei UI" />
<ComboBoxItem Content="励志立志的名言警句" FontFamily="Microsoft YaHei UI" />
<ComboBoxItem Content="高考祝福语" FontFamily="Microsoft YaHei UI" />
</ComboBox>
</ui:SimpleStackPanel>
<Line HorizontalAlignment="Center" X1="0" Y1="0" X2="400" Y2="0"
Stroke="#3f3f46" StrokeThickness="1" Margin="0,4,0,4" />
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left"> <ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<TextBlock Foreground="#fafafa" Text="在收纳模式下启用快速面板" VerticalAlignment="Center" <TextBlock Foreground="#fafafa" Text="在收纳模式下启用快速面板" VerticalAlignment="Center"
FontSize="14" Margin="0,0,16,0" /> FontSize="14" Margin="0,0,16,0" />
@ -1270,7 +1307,7 @@
FontSize="16" Foreground="White" Opacity="0.45" /> FontSize="16" Foreground="White" Opacity="0.45" />
</ui:SimpleStackPanel> </ui:SimpleStackPanel>
<TextBlock Canvas.Right="25" Canvas.Top="15" Text="多一份理解,少一份抱怨" Name="BlackBoardWaterMark" <TextBlock Canvas.Right="25" Canvas.Top="15" Text="多一份理解,少一份抱怨" Name="BlackBoardWaterMark"
Visibility="Collapsed" FontSize="30" FontWeight="Bold" Foreground="White" Opacity="0.5" /> Visibility="Collapsed" FontSize="24" FontWeight="Bold" Foreground="White" Opacity="0.5" />
</Canvas> </Canvas>
<Grid Visibility="{Binding ElementName=inkCanvas, Path=Visibility}"> <Grid Visibility="{Binding ElementName=inkCanvas, Path=Visibility}">
<Grid Name="GridInkCanvasSelectionCover" <Grid Name="GridInkCanvasSelectionCover"

View File

@ -12,6 +12,7 @@ using File = System.IO.File;
using MessageBox = System.Windows.MessageBox; using MessageBox = System.Windows.MessageBox;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Windows.Interop; using System.Windows.Interop;
using System.Windows.Controls.Primitives;
namespace Ink_Canvas { namespace Ink_Canvas {
public partial class MainWindow : Window { public partial class MainWindow : Window {
@ -173,6 +174,8 @@ namespace Ink_Canvas {
//TextBlockVersion.Text = Assembly.GetExecutingAssembly().GetName().Version.ToString(); //TextBlockVersion.Text = Assembly.GetExecutingAssembly().GetName().Version.ToString();
LogHelper.WriteLogToFile("Ink Canvas Loaded", LogHelper.LogType.Event); LogHelper.WriteLogToFile("Ink Canvas Loaded", LogHelper.LogType.Event);
FullScreenHelper.MarkFullscreenWindowTaskbarList(new WindowInteropHelper(this).Handle, true);
isLoaded = true; isLoaded = true;
} }

View File

@ -56,6 +56,7 @@ namespace Ink_Canvas {
From = new Thickness(-50, 0, 0, -150), From = new Thickness(-50, 0, 0, -150),
To = new Thickness(-1, 0, 0, -150) To = new Thickness(-1, 0, 0, -150)
}; };
marginAnimation.EasingFunction = new CubicEase();
LeftUnFoldButtonQuickPanel.BeginAnimation(MarginProperty, marginAnimation); LeftUnFoldButtonQuickPanel.BeginAnimation(MarginProperty, marginAnimation);
}); });
await Task.Delay(100); await Task.Delay(100);
@ -79,6 +80,7 @@ namespace Ink_Canvas {
From = new Thickness(0, 0, -50, -150), From = new Thickness(0, 0, -50, -150),
To = new Thickness(0, 0, -1, -150) To = new Thickness(0, 0, -1, -150)
}; };
marginAnimation.EasingFunction = new CubicEase();
RightUnFoldButtonQuickPanel.BeginAnimation(MarginProperty, marginAnimation); RightUnFoldButtonQuickPanel.BeginAnimation(MarginProperty, marginAnimation);
}); });
await Task.Delay(100); await Task.Delay(100);
@ -100,6 +102,7 @@ namespace Ink_Canvas {
From = new Thickness(-1, 0, 0, -150), From = new Thickness(-1, 0, 0, -150),
To = new Thickness(-50, 0, 0, -150) To = new Thickness(-50, 0, 0, -150)
}; };
marginAnimation.EasingFunction = new CubicEase();
LeftUnFoldButtonQuickPanel.BeginAnimation(MarginProperty, marginAnimation); LeftUnFoldButtonQuickPanel.BeginAnimation(MarginProperty, marginAnimation);
}); });
await Task.Delay(100); await Task.Delay(100);
@ -119,6 +122,7 @@ namespace Ink_Canvas {
From = new Thickness(0, 0, -1, -150), From = new Thickness(0, 0, -1, -150),
To = new Thickness(0, 0, -50, -150) To = new Thickness(0, 0, -50, -150)
}; };
marginAnimation.EasingFunction = new CubicEase();
RightUnFoldButtonQuickPanel.BeginAnimation(MarginProperty, marginAnimation); RightUnFoldButtonQuickPanel.BeginAnimation(MarginProperty, marginAnimation);
}); });
await Task.Delay(100); await Task.Delay(100);

View File

@ -166,6 +166,15 @@ namespace Ink_Canvas {
#region #region
/// <summary>
/// 隱藏形狀繪製面板
/// </summary>
private void CollapseBorderDrawShape()
{
AnimationsHelper.HideWithSlideAndFade(BorderDrawShape);
AnimationsHelper.HideWithSlideAndFade(BoardBorderDrawShape);
}
/// <summary> /// <summary>
/// <c>HideSubPanels</c>的青春版。目前需要修改<c>BorderSettings</c>的關閉機制(改為動畫關閉)。 /// <c>HideSubPanels</c>的青春版。目前需要修改<c>BorderSettings</c>的關閉機制(改為動畫關閉)。
/// </summary> /// </summary>
@ -381,6 +390,7 @@ namespace Ink_Canvas {
#endregion #endregion
#region
private void SymbolIconUndo_MouseUp(object sender, MouseButtonEventArgs e) { private void SymbolIconUndo_MouseUp(object sender, MouseButtonEventArgs e) {
//if (lastBorderMouseDownObject != sender) return; //if (lastBorderMouseDownObject != sender) return;
@ -397,64 +407,15 @@ namespace Ink_Canvas {
HideSubPanels(); HideSubPanels();
} }
private async void SymbolIconCursor_Click(object sender, RoutedEventArgs e) { #endregion
if (currentMode != 0) {
ImageBlackboard_MouseUp(null, null);
}
else {
BtnHideInkCanvas_Click(BtnHideInkCanvas, null);
if (BtnPPTSlideShowEnd.Visibility == Visibility.Visible) { #region 退
await Task.Delay(100);
ViewboxFloatingBarMarginAnimation(60);
}
}
}
private void SymbolIconDelete_MouseUp(object sender, MouseButtonEventArgs e) {
if (inkCanvas.GetSelectedStrokes().Count > 0) {
inkCanvas.Strokes.Remove(inkCanvas.GetSelectedStrokes());
GridInkCanvasSelectionCover.Visibility = Visibility.Collapsed;
}
else if (inkCanvas.Strokes.Count > 0) {
if (Settings.Automation.IsAutoSaveStrokesAtClear &&
inkCanvas.Strokes.Count > Settings.Automation.MinimumAutomationStrokeNumber) {
if (BtnPPTSlideShowEnd.Visibility == Visibility.Visible)
SaveScreenShot(true, $"{pptName}/{previousSlideID}_{DateTime.Now:HH-mm-ss}");
else
SaveScreenShot(true);
}
BtnClear_Click(null, null);
}
}
private void SymbolIconSettings_Click(object sender, RoutedEventArgs e) {
if (isOpeningOrHidingSettingsPane != false) return;
HideSubPanels();
BtnSettings_Click(null, null);
}
private void SymbolIconSelect_MouseUp(object sender, MouseButtonEventArgs e) {
FloatingbarSelectionBG.Visibility = Visibility.Visible;
System.Windows.Controls.Canvas.SetLeft(FloatingbarSelectionBG, 140);
BtnSelect_Click(null, null);
HideSubPanels("select");
}
private async void SymbolIconScreenshot_MouseUp(object sender, MouseButtonEventArgs e) {
HideSubPanelsImmediately();
await Task.Delay(50);
SaveScreenShotToDesktop();
}
//private bool Not_Enter_Blackboard_fir_Mouse_Click = true; //private bool Not_Enter_Blackboard_fir_Mouse_Click = true;
private bool isDisplayingOrHidingBlackboard = false; private bool isDisplayingOrHidingBlackboard = false;
private void ImageBlackboard_MouseUp(object sender, MouseButtonEventArgs e)
{
private void ImageBlackboard_MouseUp(object sender, MouseButtonEventArgs e) {
LeftUnFoldButtonQuickPanel.Visibility = Visibility.Collapsed; LeftUnFoldButtonQuickPanel.Visibility = Visibility.Collapsed;
RightUnFoldButtonQuickPanel.Visibility = Visibility.Collapsed; RightUnFoldButtonQuickPanel.Visibility = Visibility.Collapsed;
if (isDisplayingOrHidingBlackboard) return; if (isDisplayingOrHidingBlackboard) return;
@ -464,7 +425,8 @@ namespace Ink_Canvas {
if (inkCanvas.EditingMode == InkCanvasEditingMode.Select) PenIcon_Click(null, null); if (inkCanvas.EditingMode == InkCanvasEditingMode.Select) PenIcon_Click(null, null);
if (currentMode == 0) { if (currentMode == 0)
{
BottomViewboxPPTSidesControl.Visibility = Visibility.Collapsed; BottomViewboxPPTSidesControl.Visibility = Visibility.Collapsed;
LeftSidePanelForPPTNavigation.Visibility = Visibility.Collapsed; LeftSidePanelForPPTNavigation.Visibility = Visibility.Collapsed;
RightSidePanelForPPTNavigation.Visibility = Visibility.Collapsed; RightSidePanelForPPTNavigation.Visibility = Visibility.Collapsed;
@ -505,29 +467,55 @@ namespace Ink_Canvas {
if (isInMultiTouchMode) ToggleSwitchEnableMultiTouchMode.IsOn = false; if (isInMultiTouchMode) ToggleSwitchEnableMultiTouchMode.IsOn = false;
} }
if (Settings.Appearance.EnableTimeDisplayInWhiteboardMode == true) { if (Settings.Appearance.EnableTimeDisplayInWhiteboardMode == true)
{
WaterMarkTime.Visibility = Visibility.Visible; WaterMarkTime.Visibility = Visibility.Visible;
WaterMarkDate.Visibility = Visibility.Visible; WaterMarkDate.Visibility = Visibility.Visible;
} else {
WaterMarkTime.Visibility = Visibility.Collapsed;
WaterMarkDate.Visibility = Visibility.Collapsed;
} }
BlackBoardWaterMark.Visibility = Visibility.Visible; if (Settings.Appearance.EnableChickenSoupInWhiteboardMode == true)
if (Settings.Canvas.UsingWhiteboard) { {
BlackBoardWaterMark.Visibility = Visibility.Visible;
} else {
BlackBoardWaterMark.Visibility = Visibility.Collapsed;
}
if (Settings.Appearance.ChickenSoupSource == 0) {
int randChickenSoupIndex = new Random().Next(ChickenSoup.OSUPlayerYuLu.Length);
BlackBoardWaterMark.Text = ChickenSoup.OSUPlayerYuLu[randChickenSoupIndex];
} else if (Settings.Appearance.ChickenSoupSource == 1) {
int randChickenSoupIndex = new Random().Next(ChickenSoup.MingYanJingJu.Length);
BlackBoardWaterMark.Text = ChickenSoup.MingYanJingJu[randChickenSoupIndex];
} else if (Settings.Appearance.ChickenSoupSource == 2) {
int randChickenSoupIndex = new Random().Next(ChickenSoup.GaoKaoPhrases.Length);
BlackBoardWaterMark.Text = ChickenSoup.GaoKaoPhrases[randChickenSoupIndex];
}
if (Settings.Canvas.UsingWhiteboard)
{
ICCWaterMarkDark.Visibility = Visibility.Visible; ICCWaterMarkDark.Visibility = Visibility.Visible;
ICCWaterMarkWhite.Visibility = Visibility.Collapsed; ICCWaterMarkWhite.Visibility = Visibility.Collapsed;
} }
else { else
{
ICCWaterMarkWhite.Visibility = Visibility.Visible; ICCWaterMarkWhite.Visibility = Visibility.Visible;
ICCWaterMarkDark.Visibility = Visibility.Collapsed; ICCWaterMarkDark.Visibility = Visibility.Collapsed;
} }
} }
else { else
{
//关闭黑板 //关闭黑板
HideSubPanelsImmediately(); HideSubPanelsImmediately();
if (StackPanelPPTControls.Visibility == Visibility.Visible) { if (StackPanelPPTControls.Visibility == Visibility.Visible)
{
if (Settings.PowerPointSettings.IsShowBottomPPTNavigationPanel) if (Settings.PowerPointSettings.IsShowBottomPPTNavigationPanel)
AnimationsHelper.ShowWithSlideFromBottomAndFade(BottomViewboxPPTSidesControl); AnimationsHelper.ShowWithSlideFromBottomAndFade(BottomViewboxPPTSidesControl);
if (Settings.PowerPointSettings.IsShowSidePPTNavigationPanel) { if (Settings.PowerPointSettings.IsShowSidePPTNavigationPanel)
{
AnimationsHelper.ShowWithScaleFromLeft(LeftSidePanelForPPTNavigation); AnimationsHelper.ShowWithScaleFromLeft(LeftSidePanelForPPTNavigation);
AnimationsHelper.ShowWithScaleFromRight(RightSidePanelForPPTNavigation); AnimationsHelper.ShowWithScaleFromRight(RightSidePanelForPPTNavigation);
} }
@ -576,6 +564,77 @@ namespace Ink_Canvas {
CheckColorTheme(true); CheckColorTheme(true);
} }
#endregion
private async void SymbolIconCursor_Click(object sender, RoutedEventArgs e) {
if (currentMode != 0) {
ImageBlackboard_MouseUp(null, null);
}
else {
BtnHideInkCanvas_Click(BtnHideInkCanvas, null);
if (BtnPPTSlideShowEnd.Visibility == Visibility.Visible) {
await Task.Delay(100);
ViewboxFloatingBarMarginAnimation(60);
}
}
}
#region
private void SymbolIconDelete_MouseUp(object sender, MouseButtonEventArgs e) {
if (inkCanvas.GetSelectedStrokes().Count > 0) {
inkCanvas.Strokes.Remove(inkCanvas.GetSelectedStrokes());
GridInkCanvasSelectionCover.Visibility = Visibility.Collapsed;
}
else if (inkCanvas.Strokes.Count > 0) {
if (Settings.Automation.IsAutoSaveStrokesAtClear &&
inkCanvas.Strokes.Count > Settings.Automation.MinimumAutomationStrokeNumber) {
if (BtnPPTSlideShowEnd.Visibility == Visibility.Visible)
SaveScreenShot(true, $"{pptName}/{previousSlideID}_{DateTime.Now:HH-mm-ss}");
else
SaveScreenShot(true);
}
BtnClear_Click(null, null);
}
}
#endregion
#region
/// <summary>
/// 浮動工具欄的“套索選”按鈕事件重定向到舊UI的<c>BtnSelect_Click</c>方法
/// </summary>
/// <param name="sender">sender</param>
/// <param name="e">MouseButtonEventArgs</param>
private void SymbolIconSelect_MouseUp(object sender, MouseButtonEventArgs e)
{
FloatingbarSelectionBG.Visibility = Visibility.Visible;
System.Windows.Controls.Canvas.SetLeft(FloatingbarSelectionBG, 140);
BtnSelect_Click(null, null);
HideSubPanels("select");
}
#endregion
private void SymbolIconSettings_Click(object sender, RoutedEventArgs e) {
if (isOpeningOrHidingSettingsPane != false) return;
HideSubPanels();
BtnSettings_Click(null, null);
}
private async void SymbolIconScreenshot_MouseUp(object sender, MouseButtonEventArgs e) {
HideSubPanelsImmediately();
await Task.Delay(50);
SaveScreenShotToDesktop();
}
private void ImageCountdownTimer_MouseUp(object sender, MouseButtonEventArgs e) { private void ImageCountdownTimer_MouseUp(object sender, MouseButtonEventArgs e) {
LeftUnFoldButtonQuickPanel.Visibility = Visibility.Collapsed; LeftUnFoldButtonQuickPanel.Visibility = Visibility.Collapsed;
RightUnFoldButtonQuickPanel.Visibility = Visibility.Collapsed; RightUnFoldButtonQuickPanel.Visibility = Visibility.Collapsed;
@ -660,7 +719,7 @@ namespace Ink_Canvas {
var strokes = inkCanvas.Strokes.Clone(); var strokes = inkCanvas.Strokes.Clone();
if (inkCanvas.GetSelectedStrokes().Count != 0) strokes = inkCanvas.GetSelectedStrokes().Clone(); if (inkCanvas.GetSelectedStrokes().Count != 0) strokes = inkCanvas.GetSelectedStrokes().Clone();
int k = 1, i = 0; int k = 1, i = 0;
new Thread(new ThreadStart(() => { new Thread(() => {
foreach (var stroke in strokes) { foreach (var stroke in strokes) {
var stylusPoints = new StylusPointCollection(); var stylusPoints = new StylusPointCollection();
if (stroke.StylusPoints.Count == 629) //圆或椭圆 if (stroke.StylusPoints.Count == 629) //圆或椭圆
@ -715,7 +774,7 @@ namespace Ink_Canvas {
InkCanvasForInkReplay.Visibility = Visibility.Collapsed; InkCanvasForInkReplay.Visibility = Visibility.Collapsed;
inkCanvas.Visibility = Visibility.Visible; inkCanvas.Visibility = Visibility.Visible;
}); });
})).Start(); }).Start();
} }
private bool isStopInkReplay = false; private bool isStopInkReplay = false;
@ -1043,11 +1102,6 @@ namespace Ink_Canvas {
} }
} }
private void CollapseBorderDrawShape(bool isLongPressSelected = false) {
AnimationsHelper.HideWithSlideAndFade(BorderDrawShape);
AnimationsHelper.HideWithSlideAndFade(BoardBorderDrawShape);
}
private void DrawShapePromptToPen() { private void DrawShapePromptToPen() {
if (isLongPressSelected == true) { if (isLongPressSelected == true) {
HideSubPanels("pen"); HideSubPanels("pen");

View File

@ -49,8 +49,7 @@ namespace Ink_Canvas {
if (ToggleSwitchRunAtStartup.IsOn) { if (ToggleSwitchRunAtStartup.IsOn) {
StartAutomaticallyDel("InkCanvas"); StartAutomaticallyDel("InkCanvas");
StartAutomaticallyCreate("Ink Canvas Annotation"); StartAutomaticallyCreate("Ink Canvas Annotation");
} } else {
else {
StartAutomaticallyDel("InkCanvas"); StartAutomaticallyDel("InkCanvas");
StartAutomaticallyDel("Ink Canvas Annotation"); StartAutomaticallyDel("Ink Canvas Annotation");
} }
@ -111,8 +110,7 @@ namespace Ink_Canvas {
if (!ToggleSwitchEnableDisPlayNibModeToggle.IsOn) { if (!ToggleSwitchEnableDisPlayNibModeToggle.IsOn) {
NibModeSimpleStackPanel.Visibility = Visibility.Collapsed; NibModeSimpleStackPanel.Visibility = Visibility.Collapsed;
BoardNibModeSimpleStackPanel.Visibility = Visibility.Collapsed; BoardNibModeSimpleStackPanel.Visibility = Visibility.Collapsed;
} } else {
else {
NibModeSimpleStackPanel.Visibility = Visibility.Visible; NibModeSimpleStackPanel.Visibility = Visibility.Visible;
BoardNibModeSimpleStackPanel.Visibility = Visibility.Visible; BoardNibModeSimpleStackPanel.Visibility = Visibility.Visible;
} }
@ -162,8 +160,7 @@ namespace Ink_Canvas {
LeftUnFoldBtnImgChevron.Width = 14; LeftUnFoldBtnImgChevron.Width = 14;
LeftUnFoldBtnImgChevron.Height = 14; LeftUnFoldBtnImgChevron.Height = 14;
LeftUnFoldBtnImgChevron.RenderTransform = null; LeftUnFoldBtnImgChevron.RenderTransform = null;
} } else if (ComboBoxUnFoldBtnImg.SelectedIndex == 1) {
else if (ComboBoxUnFoldBtnImg.SelectedIndex == 1) {
RightUnFoldBtnImgChevron.Source = RightUnFoldBtnImgChevron.Source =
new BitmapImage(new Uri("pack://application:,,,/Resources/new-icons/pen-white.png")); new BitmapImage(new Uri("pack://application:,,,/Resources/new-icons/pen-white.png"));
RightUnFoldBtnImgChevron.Width = 18; RightUnFoldBtnImgChevron.Width = 18;
@ -177,6 +174,28 @@ namespace Ink_Canvas {
} }
} }
private void ComboBoxChickenSoupSource_SelectionChanged(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
Settings.Appearance.ChickenSoupSource = ComboBoxChickenSoupSource.SelectedIndex;
SaveSettingsToFile();
if (Settings.Appearance.ChickenSoupSource == 0)
{
int randChickenSoupIndex = new Random().Next(ChickenSoup.OSUPlayerYuLu.Length);
BlackBoardWaterMark.Text = ChickenSoup.OSUPlayerYuLu[randChickenSoupIndex];
}
else if (Settings.Appearance.ChickenSoupSource == 1)
{
int randChickenSoupIndex = new Random().Next(ChickenSoup.MingYanJingJu.Length);
BlackBoardWaterMark.Text = ChickenSoup.MingYanJingJu[randChickenSoupIndex];
}
else if (Settings.Appearance.ChickenSoupSource == 2)
{
int randChickenSoupIndex = new Random().Next(ChickenSoup.GaoKaoPhrases.Length);
BlackBoardWaterMark.Text = ChickenSoup.GaoKaoPhrases[randChickenSoupIndex];
}
}
private void ToggleSwitchEnableViewboxBlackBoardScaleTransform_Toggled(object sender, RoutedEventArgs e) { private void ToggleSwitchEnableViewboxBlackBoardScaleTransform_Toggled(object sender, RoutedEventArgs e) {
if (!isLoaded) return; if (!isLoaded) return;
Settings.Appearance.EnableViewboxBlackBoardScaleTransform = Settings.Appearance.EnableViewboxBlackBoardScaleTransform =
@ -188,6 +207,31 @@ namespace Ink_Canvas {
private void ToggleSwitchEnableTimeDisplayInWhiteboardMode_Toggled(object sender, RoutedEventArgs e) { private void ToggleSwitchEnableTimeDisplayInWhiteboardMode_Toggled(object sender, RoutedEventArgs e) {
if (!isLoaded) return; if (!isLoaded) return;
Settings.Appearance.EnableTimeDisplayInWhiteboardMode = ToggleSwitchEnableTimeDisplayInWhiteboardMode.IsOn; Settings.Appearance.EnableTimeDisplayInWhiteboardMode = ToggleSwitchEnableTimeDisplayInWhiteboardMode.IsOn;
if (currentMode == 1) {
if (ToggleSwitchEnableTimeDisplayInWhiteboardMode.IsOn) {
WaterMarkTime.Visibility = Visibility.Visible;
WaterMarkDate.Visibility = Visibility.Visible;
} else {
WaterMarkTime.Visibility = Visibility.Collapsed;
WaterMarkDate.Visibility = Visibility.Collapsed;
}
}
SaveSettingsToFile();
LoadSettings();
}
private void ToggleSwitchEnableChickenSoupInWhiteboardMode_Toggled(object sender, RoutedEventArgs e) {
if (!isLoaded) return;
Settings.Appearance.EnableChickenSoupInWhiteboardMode = ToggleSwitchEnableChickenSoupInWhiteboardMode.IsOn;
if (currentMode == 1) {
if (ToggleSwitchEnableTimeDisplayInWhiteboardMode.IsOn) {
BlackBoardWaterMark.Visibility = Visibility.Visible;
} else {
BlackBoardWaterMark.Visibility = Visibility.Collapsed;
}
}
SaveSettingsToFile(); SaveSettingsToFile();
LoadSettings(); LoadSettings();
} }
@ -244,8 +288,7 @@ namespace Ink_Canvas {
if (sender == ComboBoxPenStyle) { if (sender == ComboBoxPenStyle) {
Settings.Canvas.InkStyle = ComboBoxPenStyle.SelectedIndex; Settings.Canvas.InkStyle = ComboBoxPenStyle.SelectedIndex;
BoardComboBoxPenStyle.SelectedIndex = ComboBoxPenStyle.SelectedIndex; BoardComboBoxPenStyle.SelectedIndex = ComboBoxPenStyle.SelectedIndex;
} } else {
else {
Settings.Canvas.InkStyle = BoardComboBoxPenStyle.SelectedIndex; Settings.Canvas.InkStyle = BoardComboBoxPenStyle.SelectedIndex;
ComboBoxPenStyle.SelectedIndex = BoardComboBoxPenStyle.SelectedIndex; ComboBoxPenStyle.SelectedIndex = BoardComboBoxPenStyle.SelectedIndex;
} }
@ -281,8 +324,7 @@ namespace Ink_Canvas {
} }
inkCanvas.EraserShape = new EllipseStylusShape(k * 90, k * 90); inkCanvas.EraserShape = new EllipseStylusShape(k * 90, k * 90);
} } else if (Settings.Canvas.EraserShapeType == 1) {
else if (Settings.Canvas.EraserShapeType == 1) {
double k = 1; double k = 1;
switch (ComboBoxEraserSizeFloatingBar.SelectedIndex) { switch (ComboBoxEraserSizeFloatingBar.SelectedIndex) {
case 0: case 0:
@ -693,8 +735,7 @@ namespace Ink_Canvas {
inkCanvas.Children.Clear(); inkCanvas.Children.Clear();
isInMultiTouchMode = true; isInMultiTouchMode = true;
} }
} } else {
else {
if (isInMultiTouchMode) { if (isInMultiTouchMode) {
inkCanvas.StylusDown -= MainWindow_StylusDown; inkCanvas.StylusDown -= MainWindow_StylusDown;
inkCanvas.StylusMove -= MainWindow_StylusMove; inkCanvas.StylusMove -= MainWindow_StylusMove;
@ -773,6 +814,9 @@ namespace Ink_Canvas {
Settings.Appearance.IsShowModeFingerToggleSwitch = true; Settings.Appearance.IsShowModeFingerToggleSwitch = true;
Settings.Appearance.IsShowQuickPanel = true; Settings.Appearance.IsShowQuickPanel = true;
Settings.Appearance.Theme = 0; Settings.Appearance.Theme = 0;
Settings.Appearance.EnableChickenSoupInWhiteboardMode = true;
Settings.Appearance.EnableTimeDisplayInWhiteboardMode = true;
Settings.Appearance.ChickenSoupSource = 1;
Settings.Automation.IsAutoFoldInEasiNote = true; Settings.Automation.IsAutoFoldInEasiNote = true;
Settings.Automation.IsAutoFoldInEasiNoteIgnoreDesktopAnno = true; Settings.Automation.IsAutoFoldInEasiNoteIgnoreDesktopAnno = true;

View File

@ -189,6 +189,8 @@ namespace Ink_Canvas
LeftUnFoldBtnImgChevron.RenderTransform = null; LeftUnFoldBtnImgChevron.RenderTransform = null;
} }
ComboBoxChickenSoupSource.SelectedIndex = Settings.Appearance.ChickenSoupSource;
if (Settings.Appearance.IsShowQuickPanel) if (Settings.Appearance.IsShowQuickPanel)
{ {
ToggleSwitchEnableQuickPanel.IsOn = true; ToggleSwitchEnableQuickPanel.IsOn = true;
@ -248,6 +250,15 @@ namespace Ink_Canvas
ToggleSwitchEnableTimeDisplayInWhiteboardMode.IsOn = false; ToggleSwitchEnableTimeDisplayInWhiteboardMode.IsOn = false;
} }
if (Settings.Appearance.EnableChickenSoupInWhiteboardMode == true)
{
ToggleSwitchEnableChickenSoupInWhiteboardMode.IsOn = true;
}
else
{
ToggleSwitchEnableChickenSoupInWhiteboardMode.IsOn = false;
}
SystemEvents_UserPreferenceChanged(null, null); SystemEvents_UserPreferenceChanged(null, null);
} }
else else
@ -473,11 +484,19 @@ namespace Ink_Canvas
if (Settings.Canvas.UsingWhiteboard) if (Settings.Canvas.UsingWhiteboard)
{ {
GridBackgroundCover.Background = new SolidColorBrush(StringToColor("#FFF2F2F2")); GridBackgroundCover.Background = new SolidColorBrush(Color.FromRgb(234, 235, 237));
WaterMarkTime.Foreground = new SolidColorBrush(Color.FromRgb(22, 41, 36));
WaterMarkDate.Foreground = new SolidColorBrush(Color.FromRgb(22, 41, 36));
BlackBoardWaterMark.Foreground = new SolidColorBrush(Color.FromRgb(22, 41, 36));
isUselightThemeColor = false;
} }
else else
{ {
GridBackgroundCover.Background = new SolidColorBrush(StringToColor("#FF1F1F1F")); GridBackgroundCover.Background = new SolidColorBrush(Color.FromRgb(22, 41, 36));
WaterMarkTime.Foreground = new SolidColorBrush(Color.FromRgb(234, 235, 237));
WaterMarkDate.Foreground = new SolidColorBrush(Color.FromRgb(234, 235, 237));
BlackBoardWaterMark.Foreground = new SolidColorBrush(Color.FromRgb(234, 235, 237));
isUselightThemeColor = true;
} }
if (Settings.Canvas.IsShowCursor) if (Settings.Canvas.IsShowCursor)

View File

@ -107,7 +107,7 @@ namespace Ink_Canvas {
lastMouseDownSender = null; lastMouseDownSender = null;
if (isLongPressSelected) { if (isLongPressSelected) {
if (ToggleSwitchDrawShapeBorderAutoHide.IsOn) CollapseBorderDrawShape(true); if (ToggleSwitchDrawShapeBorderAutoHide.IsOn) CollapseBorderDrawShape();
var dA = new DoubleAnimation(1, 1, new Duration(TimeSpan.FromMilliseconds(0))); var dA = new DoubleAnimation(1, 1, new Duration(TimeSpan.FromMilliseconds(0)));
ImageDrawLine.BeginAnimation(OpacityProperty, dA); ImageDrawLine.BeginAnimation(OpacityProperty, dA);
} }
@ -127,7 +127,7 @@ namespace Ink_Canvas {
lastMouseDownSender = null; lastMouseDownSender = null;
if (isLongPressSelected) { if (isLongPressSelected) {
if (ToggleSwitchDrawShapeBorderAutoHide.IsOn) CollapseBorderDrawShape(true); if (ToggleSwitchDrawShapeBorderAutoHide.IsOn) CollapseBorderDrawShape();
var dA = new DoubleAnimation(1, 1, new Duration(TimeSpan.FromMilliseconds(0))); var dA = new DoubleAnimation(1, 1, new Duration(TimeSpan.FromMilliseconds(0)));
ImageDrawDashedLine.BeginAnimation(OpacityProperty, dA); ImageDrawDashedLine.BeginAnimation(OpacityProperty, dA);
} }
@ -147,7 +147,7 @@ namespace Ink_Canvas {
lastMouseDownSender = null; lastMouseDownSender = null;
if (isLongPressSelected) { if (isLongPressSelected) {
if (ToggleSwitchDrawShapeBorderAutoHide.IsOn) CollapseBorderDrawShape(true); if (ToggleSwitchDrawShapeBorderAutoHide.IsOn) CollapseBorderDrawShape();
var dA = new DoubleAnimation(1, 1, new Duration(TimeSpan.FromMilliseconds(0))); var dA = new DoubleAnimation(1, 1, new Duration(TimeSpan.FromMilliseconds(0)));
ImageDrawDotLine.BeginAnimation(OpacityProperty, dA); ImageDrawDotLine.BeginAnimation(OpacityProperty, dA);
} }
@ -167,7 +167,7 @@ namespace Ink_Canvas {
lastMouseDownSender = null; lastMouseDownSender = null;
if (isLongPressSelected) { if (isLongPressSelected) {
if (ToggleSwitchDrawShapeBorderAutoHide.IsOn) CollapseBorderDrawShape(true); if (ToggleSwitchDrawShapeBorderAutoHide.IsOn) CollapseBorderDrawShape();
var dA = new DoubleAnimation(1, 1, new Duration(TimeSpan.FromMilliseconds(0))); var dA = new DoubleAnimation(1, 1, new Duration(TimeSpan.FromMilliseconds(0)));
ImageDrawArrow.BeginAnimation(OpacityProperty, dA); ImageDrawArrow.BeginAnimation(OpacityProperty, dA);
} }
@ -187,7 +187,7 @@ namespace Ink_Canvas {
lastMouseDownSender = null; lastMouseDownSender = null;
if (isLongPressSelected) { if (isLongPressSelected) {
if (ToggleSwitchDrawShapeBorderAutoHide.IsOn) CollapseBorderDrawShape(true); if (ToggleSwitchDrawShapeBorderAutoHide.IsOn) CollapseBorderDrawShape();
var dA = new DoubleAnimation(1, 1, new Duration(TimeSpan.FromMilliseconds(0))); var dA = new DoubleAnimation(1, 1, new Duration(TimeSpan.FromMilliseconds(0)));
ImageDrawParallelLine.BeginAnimation(OpacityProperty, dA); ImageDrawParallelLine.BeginAnimation(OpacityProperty, dA);
} }

View File

@ -0,0 +1,118 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Ink_Canvas
{
public static class ChickenSoup {
public static string[] OSUPlayerYuLu = new string[] {
"澳洲原神,启动!",
"一眼丁真鉴定为玩osu!玩的",
"喊MimosaM给我炒两菜",
"不要……不要把背景圖刪掉的說!",
"6秒800PPI Can",
"osu! 启动!",
"你说得对但是osu!,前面忘了,后面忘了",
"换电脑变成残疾人",
"难绷acc",
"牢大这是串pp图啊",
"你看人家坚持不刷PP都在新人群买房了",
"打o不要这么努力吧",
"凹不了一点",
"大神进步好快啊",
"pass和fc之间是天堑",
"4星就是一个巨大的开放暴毙世界",
"我是要成为owc选手的人",
"戳完就跳",
"我疑似有点罕见了",
"小时候喝了这个手指学会了强双",
"90bpm熬老头呢",
"艹了发现我从没fc过一张串图",
"oshit!",
"hso!",
"不好玩!",
"钝角跳真的挺恶心的",
"我草O",
"又有人2000了"
};
public static string[] MingYanJingJu = new string[] {
"老骥伏枥,志在千里;烈士暮年,壮心不已",
"有志者,事竟成",
"有志者自有千方百计,无志者只感千难万难",
"有志的人战天斗地,无志的人怨天恨地",
"有伟大志向的人,都可以成为圣人。",
"人的志向,应在千里之外。",
"人不在于地位的高低,而在于志向的远大。",
"人的志向,应崇高而远大。",
"立志没有所谓过迟",
"鸟不展翅膀难高飞",
"不怕路远,就怕志短",
"当今之世,舍我其谁",
"立志不坚,终不济事",
"鸟贵有翼,人贵有志",
"少年立志要远大,持身要紧严立志不高,则溺于流俗;",
"持身不严,则入于匪辞",
"人若有志,万事可为",
"心志要坚,意趣要乐",
"胸无大志,枉活一世",
"燕雀安知鸿鹄之志哉",
"一人立志,万夫莫敌",
"鹰爱高飞,鸦栖一枝",
"治天下者必先立其志",
"强行者有志",
"志当存高远",
"百学须先立志",
"以天下为己任",
"志,气之帅也",
"才自清明志自高",
"褴褛衣内可藏志",
"无所求则无所获",
"慷慨丈夫志,可以耀锋芒",
"母鸡的理想不过是一把糠",
"男儿千年志,吾生未有涯",
"男儿四方志,岂久困泥沙",
"男子千年志,吾生未有涯",
"穷且益坚,不坠青云之志",
"人生志气立,所贵功业昌",
"生无一锥土,常有四海心",
"无志愁压头,有志能搬山",
"心随朗月高,志与秋霜洁",
"胸有凌云志,无高不可攀",
"雄心志四海,万里望风尘",
"一分事业心能抵十分特权",
"有志登山顶,无志站山脚",
"丈夫清万里,谁能扫一室",
"丈夫四海志,万里犹比邻",
"丈夫志不大,何以佐乾坤",
"丈夫志气薄,儿女安得知",
"志不立,天下无可成之事",
"志高山峰矮,路从脚下伸",
"壮志与毅力是事业的双翼",
"成功是别人失败时还在坚持",
"贫不足羞,可羞是贫而无志",
"虽长不满七尺,而心雄万丈",
"有志者能使石头长出青草来",
"志之难也,不在胜人,在自胜",
"有志始知蓬莱近,无为总觉咫尺远",
"不要在夕阳西下时幻想,要在旭日东升时努力",
"立志是事业的大门,工作是登门入室的的旅途",
"一个人如果胸无大志,既使再有壮丽的举动也称不上是伟人",
"志不立,如无舵这舟,无衔之马,漂荡奔逸,终亦何所底乎",
"有志不在年高,无志空活百岁",
};
public static string[] GaoKaoPhrases = new string[] {
"以梦为马,不负韶华。祝你高考顺利,未来可期!",
"高考顺利,愿你乘风破浪,前程似锦!",
"愿你高考顺利,不负韶华,梦想成真!",
"高考必胜,愿你展翅高飞,未来可期!",
"愿你不畏困难,勇往直前,高考成绩如你所愿,未来更加光明。",
"高考将至,愿你所学皆精,所考皆通,一鸣惊人,一举夺魁!",
"十年磨一剑,今朝试锋芒。高考顺利,未来可期!",
"恭祝,恭祝,此战青云平步。祝高考金榜题名。",
};
}
}

View File

@ -125,6 +125,8 @@ namespace Ink_Canvas
public bool IsShowEraserButton { get; set; } = true; public bool IsShowEraserButton { get; set; } = true;
[JsonProperty("enableTimeDisplayInWhiteboardMode")] [JsonProperty("enableTimeDisplayInWhiteboardMode")]
public bool EnableTimeDisplayInWhiteboardMode { get; set; } = true; public bool EnableTimeDisplayInWhiteboardMode { get; set; } = true;
[JsonProperty("enableChickenSoupInWhiteboardMode")]
public bool EnableChickenSoupInWhiteboardMode { get; set; } = true;
[JsonProperty("isShowHideControlButton")] [JsonProperty("isShowHideControlButton")]
public bool IsShowHideControlButton { get; set; } = false; public bool IsShowHideControlButton { get; set; } = false;
[JsonProperty("unFoldButtonImageType")] [JsonProperty("unFoldButtonImageType")]
@ -133,6 +135,8 @@ namespace Ink_Canvas
public bool IsShowLRSwitchButton { get; set; } = false; public bool IsShowLRSwitchButton { get; set; } = false;
[JsonProperty("isShowQuickPanel")] [JsonProperty("isShowQuickPanel")]
public bool IsShowQuickPanel { get; set; } = true; public bool IsShowQuickPanel { get; set; } = true;
[JsonProperty("chickenSoupSource")]
public int ChickenSoupSource { get; set; } = 1;
[JsonProperty("isShowModeFingerToggleSwitch")] [JsonProperty("isShowModeFingerToggleSwitch")]
public bool IsShowModeFingerToggleSwitch { get; set; } = true; public bool IsShowModeFingerToggleSwitch { get; set; } = true;
[JsonProperty("theme")] [JsonProperty("theme")]