Skip to content

Commit

Permalink
One.Toolbox
Browse files Browse the repository at this point in the history
新增Stick贴边自动隐藏的功能;
  • Loading branch information
panwenbo committed Jan 11, 2024
1 parent eea2bbf commit 9c1d29c
Show file tree
Hide file tree
Showing 6 changed files with 297 additions and 16 deletions.
253 changes: 253 additions & 0 deletions One.Toolbox/Helpers/HideWindowHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Windows.Media;
using System.Windows.Media.Animation;

using Timer = System.Windows.Forms.Timer;

namespace One.Toolbox.Helpers;

internal partial class HideWindowHelper
{
private readonly Window _window;
private readonly Timer _timer;
private readonly List<HideCore> _hideLogicList = new List<HideCore>();

[LibraryImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static partial bool GetCursorPos(out Point pt);

private struct Point
{
public int X;
public int Y;

// ReSharper disable once UnusedMember.Local
public Point(int x, int y)
{
X = x;
Y = y;
}
}

private bool _isHide;
private bool _isStarted;
private HideCore _lastHiderOn;
private bool _isInAnimation;

private HideWindowHelper(Window window)
{
_window = window;
_timer = new Timer { Interval = 300 };
_timer.Tick += _timer_Tick;
}

public HideWindowHelper AddHider<THideCore>() where THideCore : HideCore, new()
{
if (_isStarted) throw new Exception("调用了Start方法后无法在添加隐藏逻辑");
var logic = new THideCore();
logic.Init(_window, AnimationReport);
_hideLogicList.Add(logic);
return this;
}

private void _timer_Tick(object sender, EventArgs e)
{
if (_isInAnimation) return;
if (_window.IsActive) return;
GetCursorPos(out var point); //获取鼠标相对桌面的位置
var isMouseEnter = point.X >= _window.Left
&& point.X <= _window.Left + _window.Width + 30
&& point.Y >= _window.Top
&& point.Y <= _window.Top
+ _window.Height + 30;
//鼠标在里面
if (isMouseEnter)
{
//没有隐藏,直接返回
if (!_isHide) return;

//理论上不会出现为null的情况
if (_lastHiderOn != null)
{
_lastHiderOn.Show();
_isHide = false;
_window.ShowInTaskbar = true;
return;
}
}

foreach (var core in _hideLogicList)
{
//鼠标在里面并且没有隐藏
if (isMouseEnter && !_isHide) return;

//鼠标在里面并且当期是隐藏状态且当前处理器成功显示了窗体
if (isMouseEnter && _isHide && core.Show())
{
_isHide = false;
_window.ShowInTaskbar = true;
return;
}

//鼠标在外面并且没有隐藏,那么调用当前处理器尝试隐藏窗体
if (!isMouseEnter && !_isHide && core.Hide())
{
_lastHiderOn = core;
_isHide = true;
_window.ShowInTaskbar = false;
return;
}
}
}

private void AnimationReport(bool isInAnimation)
{
_isInAnimation = isInAnimation;
}

/// <summary>
/// 启动隐藏
/// </summary>
/// <returns></returns>
public HideWindowHelper Start()
{
_isStarted = true;
_timer.Start();
return this;
}

public void Stop()
{
_timer.Stop();
_isStarted = false;
}

public static HideWindowHelper CreateFor(Window window)
{
return new HideWindowHelper(window);
}

/// <summary>
/// 用代码触发显示,适用于双击任务栏图标
/// </summary>
public void TryShow()
{
if (_lastHiderOn == null) return;
_lastHiderOn.Show();
_isHide = false;
_window.Activate();
}
}

#region 隐藏逻辑基类

public abstract class HideCore
{
private Window _window;
private Action<bool> _animationStateReport;

internal void Init(Window window, Action<bool> animationStateReport)
{
_window = window;
_animationStateReport = animationStateReport;
}

public abstract bool Show();

public abstract bool Hide();

protected Window WindowInstance => _window;

protected void StartAnimation(DependencyProperty property, double from, double to)
{
_animationStateReport(true);
var doubleAnimation = new DoubleAnimation(from, to, TimeSpan.FromSeconds(0.3));
doubleAnimation.EasingFunction = new QuadraticEase();//允许你指定动画的缓动效果,可以使窗口的位置变化更加平滑。

doubleAnimation.Completed += delegate
{
_window.BeginAnimation(property, null);
_animationStateReport(false);
};
_window.BeginAnimation(property, doubleAnimation);
}
}

#endregion 隐藏逻辑基类

#region 向上隐藏

internal class HideOnTop : HideCore
{
//RenderTransform 的帧动画在某些情况下可能会比直接控制窗口的动画效果更丝滑。这是因为 RenderTransform 的动画是在 GPU 上执行的,而直接控制窗口的动画是在 CPU 上执行的。
public override bool Show()
{
if (WindowInstance.Top > 0) return false;
StartAnimation(Window.TopProperty, WindowInstance.Top, 0);
return true;
}

public override bool Hide()
{
if (WindowInstance.Top > 2) return false;

StartAnimation(Window.TopProperty, WindowInstance.Top, 0 - WindowInstance.Top - WindowInstance.Height + 2);

return true;
}
}

#endregion 向上隐藏

#region 向左隐藏

internal class HideOnLeft : HideCore
{
public override bool Show()
{
if (WindowInstance.Left > 0) return false;
StartAnimation(Window.LeftProperty, WindowInstance.Left, 0);
return true;
}

public override bool Hide()
{
if (WindowInstance.Left > 2) return false;
StartAnimation(Window.LeftProperty, WindowInstance.Left, 0 - WindowInstance.Width + 2);
return true;
}
}

#endregion 向左隐藏

#region 向右隐藏

internal class HideOnRight : HideCore
{
private readonly int _screenWidth;

public HideOnRight()
{
foreach (var screen in Screen.AllScreens)
{
_screenWidth += screen.Bounds.Width;
}
}

public override bool Show()
{
if (_screenWidth - WindowInstance.Left - WindowInstance.Width > 0) return false;
StartAnimation(Window.LeftProperty, WindowInstance.Left, _screenWidth - WindowInstance.Width);
return true;
}

public override bool Hide()
{
if (_screenWidth - WindowInstance.Left - WindowInstance.Width > 2) return false;
StartAnimation(Window.LeftProperty, WindowInstance.Left, _screenWidth - 2);
return true;
}
}

#endregion 向右隐藏
2 changes: 1 addition & 1 deletion One.Toolbox/One.Toolbox.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<SelfContained>false</SelfContained>
<UseWPF>true</UseWPF>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<Version>2.6.7</Version>
<Version>2.6.8</Version>
<ImplicitUsings>enable</ImplicitUsings>
<SatelliteResourceLanguages>zh-Hans;en-us</SatelliteResourceLanguages>
<ApplicationIcon>Icon.ico</ApplicationIcon>
Expand Down
13 changes: 11 additions & 2 deletions One.Toolbox/ViewModels/Stick/StickItemVM.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;

namespace One.Toolbox.ViewModels.Stick;
Expand Down Expand Up @@ -188,6 +189,14 @@ private void InitRtbControl(object obj)

#region UpCommand

private Window MyWindow;

[RelayCommand]
private void Loaded(object obj)
{
MyWindow = obj as Window;
}

[RelayCommand]
private async Task RenameStick(object obj)
{
Expand Down Expand Up @@ -236,8 +245,8 @@ private void CloseWnd(object obj)
try
{
SaveSetting();
var wnd = (Window)obj;
wnd.Close();
var rootWnd = (Window)obj;
rootWnd.Close();
}
catch (Exception)
{
Expand Down
2 changes: 1 addition & 1 deletion One.Toolbox/Views/Stick/StickPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:uc="clr-namespace:One.Toolbox.MyUserControl"
xmlns:uc="clr-namespace:One.Toolbox.MyUserControl"
xmlns:vms="clr-namespace:One.Toolbox.ViewModels.Stick"
d:DataContext="{d:DesignInstance vms:StickPageVM,
IsDesignTimeCreatable=False}"
Expand Down
23 changes: 15 additions & 8 deletions One.Toolbox/Views/Stick/StickWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,36 @@
xmlns:oc="clr-namespace:One.Control.Controls.RichTextboxEx;assembly=One.Control"
xmlns:ocu="clr-namespace:One.Control.Utilities;assembly=One.Control"
xmlns:vms="clr-namespace:One.Toolbox.ViewModels.Stick"
x:Name="wnd"
Title="StickWindow"
Width="200"
Height="250"
x:Name="rootWnd"
Title="StickWindow" ResizeMode="NoResize"
Width="200"
Height="250"
d:DataContext="{d:DesignInstance Type=vms:StickItemVM}"
d:DesignHeight="450"
d:DesignWidth="300"
BorderThickness="0"
ShowInTaskbar="False"
ShowNonClientArea="False"
mc:Ignorable="d">
mc:Ignorable="d" Loaded="rootWnd_Loaded" RenderTransformOrigin="0.5,0.5">
<hc:Window.Resources>

<Style x:Key="RichTextBoxStyle1" BasedOn="{StaticResource TextBoxBaseBaseStyle}" TargetType="{x:Type RichTextBox}">
<Setter Property="MinWidth" Value="10" />
</Style>

<ocu:BindingProxy x:Key="proxy" Data="{Binding}" />



</hc:Window.Resources>

<behaviors:Interaction.Triggers>
<behaviors:EventTrigger EventName="Deactivated">
<behaviors:InvokeCommandAction Command="{Binding DeactivatedWndCommand}" />
</behaviors:EventTrigger>
<behaviors:EventTrigger EventName="Loaded">
<behaviors:InvokeCommandAction Command="{Binding LoadedCommand}" CommandParameter="{Binding ElementName=rootWnd}" />
</behaviors:EventTrigger>
</behaviors:Interaction.Triggers>
<Grid>
<Grid.RowDefinitions>
Expand All @@ -53,7 +60,7 @@
<!--<TextBlock Margin="5" VerticalAlignment="Center" Text="{Binding StickType}" />-->
</StackPanel>
<Border Grid.Column="1" />
<StackPanel Grid.Column="2" Orientation="Horizontal" Visibility="{Binding ElementName=wnd, Path=IsActive, Converter={StaticResource BoolToVisibilityConverter}, UpdateSourceTrigger=LostFocus}">
<StackPanel Grid.Column="2" Orientation="Horizontal" Visibility="{Binding ElementName=rootWnd, Path=IsActive, Converter={StaticResource BoolToVisibilityConverter}, UpdateSourceTrigger=LostFocus}">
<StackPanel.Resources>
<Style BasedOn="{StaticResource ButtonIcon.Small}" TargetType="Button" />
</StackPanel.Resources>
Expand All @@ -78,7 +85,7 @@
</Border>
</Popup>

<Button hc:IconElement.Geometry="{StaticResource CloseGeometry}" Command="{Binding CloseWndCommand}" CommandParameter="{Binding ElementName=wnd}" />
<Button hc:IconElement.Geometry="{StaticResource CloseGeometry}" Command="{Binding CloseWndCommand}" CommandParameter="{Binding ElementName=rootWnd}" />
</StackPanel>
</Grid>
</Border>
Expand Down Expand Up @@ -116,7 +123,7 @@
X2="{Binding ElementName=bottomGrid, Path=ActualWidth}"
Y1="0" Y2="0" />

<StackPanel Grid.Row="1" Orientation="Horizontal" Visibility="{Binding ElementName=wnd, Path=IsActive, Converter={StaticResource BoolToVisibilityConverter}, UpdateSourceTrigger=LostFocus}">
<StackPanel Grid.Row="1" Orientation="Horizontal" Visibility="{Binding ElementName=rootWnd, Path=IsActive, Converter={StaticResource BoolToVisibilityConverter}, UpdateSourceTrigger=LostFocus}">
<StackPanel.Resources>
<Style BasedOn="{StaticResource ButtonIcon.Small}" TargetType="Button" />
</StackPanel.Resources>
Expand Down
Loading

0 comments on commit 9c1d29c

Please sign in to comment.