Last active
March 24, 2025 00:19
-
-
Save tor4kichi/18fa130a181f79f99657b94edd9889ce to your computer and use it in GitHub Desktop.
矩形を変形するためのコントロールの試作【UWP】
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ## SquereSizerコントロール | |
| 矩形の変形操作をサポートしたコントロールです。 | |
| MinMaxサイズ、MinMaxエリアの中で変形します | |
| 角の部分をThumb、上下左右の線をLine、移動操作をPositionとしています。 | |
| PositionBehaviorを移動可能範囲を制御できます。Area内(InsideArea)、Areaに接地(IntersectArea)、無制限(Free)。 | |
| FrameworkElementのプロパティを使って制御する部分 | |
| * Width/Height | |
| * MinWidth/MaxWidth | |
| * MinHeight/MaxHeight | |
| * Background | |
| 独自定義のプロパティ | |
| * LineWidth | |
| * LinePadding | |
| * LineBackgroundBrush | |
| * PositionBehavior | |
| * Position | |
| * AreaTopLeft | |
| * AreaBottomRight | |
| * ThumbWidth | |
| * ThumbMargin | |
| * ThumbStrokeBrush | |
| * ThumbBackground | |
| ## ライセンス | |
| CC0 1.0 Universal (CC0 1.0) パブリックドメイン献納声明 著作権者は、この著作物を、世界中で適用可能なすべての著作権法および関連する権利に基づいてパブリックドメインに献納します。これにより、誰もがいかなる目的でも自由に使用、改変、再配布することができます。 | |
| 詳細なライセンス文は、以下のクリエイティブ・コモンズ公式サイトで確認できます: [CC0公式ページ](https://creativecommons.org/publicdomain/zero/1.0/) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <UserControl x:Class="TransformToolkit.SquereSizer" | |
| xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | |
| xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | |
| xmlns:local="using:TransformToolkit" | |
| xmlns:d="http://schemas.microsoft.com/expression/blend/2008" | |
| xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" | |
| xmlns:toolkit="using:CommunityToolkit.WinUI" | |
| mc:Ignorable="d" | |
| d:DesignHeight="300" | |
| d:DesignWidth="400" | |
| > | |
| <UserControl.Resources> | |
| <Style x:Key="ThumbOuterBorderStyle" | |
| TargetType="Border"> | |
| <Setter Property="RenderTransformOrigin" | |
| Value="0.5, 0.5" /> | |
| <Setter Property="IsHitTestVisible" | |
| Value="True" /> | |
| <Setter Property="Background" | |
| Value="Transparent" /> | |
| </Style> | |
| <Style x:Key="ThumbInnerBorderStyle" | |
| TargetType="Border"> | |
| <Setter Property="Width" | |
| Value="{x:Bind ThumbWidth, Mode=OneWay}" /> | |
| <Setter Property="Height" | |
| Value="{x:Bind ThumbWidth, Mode=OneWay}" /> | |
| <Setter Property="CornerRadius" | |
| Value="60" /> | |
| <Setter Property="BorderThickness" | |
| Value="1" /> | |
| <Setter Property="BorderBrush" | |
| Value="{ThemeResource SystemAccentColor}" /> | |
| <Setter Property="Background" | |
| Value="{ThemeResource ApplicationPageBackgroundThemeBrush}" /> | |
| </Style> | |
| <Style x:Key="LineInnerBorderStyle" | |
| TargetType="Border"> | |
| <Setter Property="Background" | |
| Value="{x:Bind BorderBrush, Mode=OneWay}" /> | |
| </Style> | |
| <Style x:Key="LineOuterBorderStyle" | |
| TargetType="Border"> | |
| <Setter Property="Background" | |
| Value="{x:Bind LineBackgroundBrush, Mode=OneWay}" /> | |
| <Setter Property="IsHitTestVisible" | |
| Value="True" /> | |
| </Style> | |
| </UserControl.Resources> | |
| <Grid Margin="{x:Bind Padding, Mode=OneWay}"> | |
| <Grid x:Name="RootGrid" | |
| Background="{x:Bind Background, Mode=OneWay}"> | |
| <Grid.RenderTransform> | |
| <CompositeTransform x:Name="RootGrid_Transform" /> | |
| </Grid.RenderTransform> | |
| <Border x:Name="ChangePositionTrapBorder" | |
| Background="Transparent" | |
| IsHitTestVisible="True" | |
| PointerPressed="ChangePositionTrapBorder_PointerPressed" | |
| toolkit:FrameworkElementExtensions.Cursor="SizeAll" | |
| /> | |
| <Border x:Name="Top_Line_Outer" | |
| VerticalAlignment="Top" | |
| toolkit:FrameworkElementExtensions.Cursor="SizeNorthSouth" | |
| PointerPressed="Thumb_PointerPressed" | |
| Style="{StaticResource LineOuterBorderStyle}" | |
| Padding="{x:Bind ToVerticalThickness(LinePadding), Mode=OneWay}"> | |
| <Border.RenderTransform> | |
| <TranslateTransform x:Name="Top_OuterLine_Transform" /> | |
| </Border.RenderTransform> | |
| <Border x:Name="Top_Line" | |
| Height="{x:Bind LineWidth, Mode=OneWay}" | |
| Style="{StaticResource LineInnerBorderStyle}"> | |
| <Border.RenderTransform> | |
| <TranslateTransform x:Name="Top_InnerLine_Transform" /> | |
| </Border.RenderTransform> | |
| </Border> | |
| </Border> | |
| <Border x:Name="Bottom_Line_Outer" | |
| VerticalAlignment="Bottom" | |
| toolkit:FrameworkElementExtensions.Cursor="SizeNorthSouth" | |
| PointerPressed="Thumb_PointerPressed" | |
| Style="{StaticResource LineOuterBorderStyle}" | |
| Padding="{x:Bind ToVerticalThickness(LinePadding), Mode=OneWay}"> | |
| <Border.RenderTransform> | |
| <TranslateTransform x:Name="Bottom_OuterLine_Transform" /> | |
| </Border.RenderTransform> | |
| <Border x:Name="Bottom_Line" | |
| Height="{x:Bind LineWidth, Mode=OneWay}" | |
| Style="{StaticResource LineInnerBorderStyle}"> | |
| <Border.RenderTransform> | |
| <TranslateTransform x:Name="Bottom_InnerLine_Transform" /> | |
| </Border.RenderTransform> | |
| </Border> | |
| </Border> | |
| <Border x:Name="Right_Line_Outer" | |
| HorizontalAlignment="Right" | |
| toolkit:FrameworkElementExtensions.Cursor="SizeWestEast" | |
| PointerPressed="Thumb_PointerPressed" | |
| Style="{StaticResource LineOuterBorderStyle}" | |
| Padding="{x:Bind ToHorizontalThickness(LinePadding), Mode=OneWay}"> | |
| <Border.RenderTransform> | |
| <TranslateTransform x:Name="Right_OuterLine_Transform" /> | |
| </Border.RenderTransform> | |
| <Border x:Name="Right_Line" | |
| Width="{x:Bind LineWidth, Mode=OneWay}" | |
| Style="{StaticResource LineInnerBorderStyle}"> | |
| <Border.RenderTransform> | |
| <TranslateTransform x:Name="Right_InnerLine_Transform" /> | |
| </Border.RenderTransform> | |
| </Border> | |
| </Border> | |
| <Border x:Name="Left_Line_Outer" | |
| HorizontalAlignment="Left" | |
| toolkit:FrameworkElementExtensions.Cursor="SizeWestEast" | |
| PointerPressed="Thumb_PointerPressed" | |
| Style="{StaticResource LineOuterBorderStyle}" | |
| Padding="{x:Bind ToHorizontalThickness(LinePadding), Mode=OneWay}"> | |
| <Border.RenderTransform> | |
| <TranslateTransform x:Name="Left_OuterLine_Transform" /> | |
| </Border.RenderTransform> | |
| <Border x:Name="Left_Line_Inner" | |
| Width="{x:Bind LineWidth, Mode=OneWay}" | |
| Style="{StaticResource LineInnerBorderStyle}"> | |
| <Border.RenderTransform> | |
| <TranslateTransform x:Name="Left_InnerLine_Transform" /> | |
| </Border.RenderTransform> | |
| </Border> | |
| </Border> | |
| <Border x:Name="TopLeft_Thumb_Outer" | |
| Style="{StaticResource ThumbOuterBorderStyle}" | |
| HorizontalAlignment="Left" | |
| VerticalAlignment="Top" | |
| toolkit:FrameworkElementExtensions.Cursor="SizeNorthwestSoutheast" | |
| PointerPressed="Thumb_PointerPressed" | |
| Padding="{x:Bind ThumbMargin, Mode=OneWay}"> | |
| <Border.RenderTransform> | |
| <TranslateTransform x:Name="TopLeft_Thumb_Transform" /> | |
| </Border.RenderTransform> | |
| <Border x:Name="TopLeft_Thumb_Inner" | |
| Style="{StaticResource ThumbInnerBorderStyle}" /> | |
| </Border> | |
| <Border x:Name="TopRight_Thumb_Outer" | |
| Style="{StaticResource ThumbOuterBorderStyle}" | |
| HorizontalAlignment="Right" | |
| VerticalAlignment="Top" | |
| toolkit:FrameworkElementExtensions.Cursor="SizeNortheastSouthwest" | |
| PointerPressed="Thumb_PointerPressed" | |
| Padding="{x:Bind ThumbMargin, Mode=OneWay}"> | |
| <Border.RenderTransform> | |
| <TranslateTransform x:Name="TopRight_Thumb_Transform" /> | |
| </Border.RenderTransform> | |
| <Border x:Name="TopRight_Thumb_Inner" | |
| Style="{StaticResource ThumbInnerBorderStyle}" /> | |
| </Border> | |
| <Border x:Name="BottomLeft_Thumb_Outer" | |
| Style="{StaticResource ThumbOuterBorderStyle}" | |
| HorizontalAlignment="Left" | |
| VerticalAlignment="Bottom" | |
| toolkit:FrameworkElementExtensions.Cursor="SizeNortheastSouthwest" | |
| PointerPressed="Thumb_PointerPressed" | |
| Padding="{x:Bind ThumbMargin, Mode=OneWay}"> | |
| <Border.RenderTransform> | |
| <TranslateTransform x:Name="BottomLeft_Thumb_Transform" /> | |
| </Border.RenderTransform> | |
| <Border x:Name="BottomLeft_Thumb_Inner" | |
| Style="{StaticResource ThumbInnerBorderStyle}" /> | |
| </Border> | |
| <Border x:Name="BottomRight_Thumb_Outer" | |
| Style="{StaticResource ThumbOuterBorderStyle}" | |
| HorizontalAlignment="Right" | |
| VerticalAlignment="Bottom" | |
| toolkit:FrameworkElementExtensions.Cursor="SizeNorthwestSoutheast" | |
| PointerPressed="Thumb_PointerPressed" | |
| Padding="{x:Bind ThumbMargin, Mode=OneWay}"> | |
| <Border.RenderTransform> | |
| <TranslateTransform x:Name="BottomRight_Thumb_Transform" /> | |
| </Border.RenderTransform> | |
| <Border x:Name="BottomRight_Thumb_Inner" | |
| Style="{StaticResource ThumbInnerBorderStyle}" /> | |
| </Border> | |
| </Grid> | |
| </Grid> | |
| </UserControl> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Diagnostics; | |
| using System.Numerics; | |
| using Windows.Foundation; | |
| using Windows.UI; | |
| using Windows.UI.Xaml; | |
| using Windows.UI.Xaml.Controls; | |
| using Windows.UI.Xaml.Input; | |
| using Windows.UI.Xaml.Media; | |
| #nullable enable | |
| namespace TransformToolkit; | |
| public sealed partial class SquereSizer : UserControl | |
| { | |
| public SquereSizer() | |
| { | |
| this.InitializeComponent(); | |
| Loaded += SquereSizer_Loaded; | |
| } | |
| private void SquereSizer_Loaded(object sender, RoutedEventArgs e) | |
| { | |
| ApplyThumbSizeFromThumbWidth(); | |
| ApplyLineCenterOffset(); | |
| ApplyInnerLineCenterOffset(); | |
| } | |
| public double LineWidth | |
| { | |
| get { return (double)GetValue(LineWidthProperty); } | |
| set { SetValue(LineWidthProperty, value); } | |
| } | |
| public static readonly DependencyProperty LineWidthProperty = | |
| DependencyProperty.Register("LineWidth", typeof(double), typeof(SquereSizer), new PropertyMetadata(1.0d, OnLineWidthPropertyChanged)); | |
| private static void OnLineWidthPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) | |
| { | |
| var _this = (SquereSizer)d; | |
| _this.ApplyLineCenterOffset(); | |
| _this.ApplyInnerLineCenterOffset(); | |
| } | |
| public double LinePadding | |
| { | |
| get { return (double)GetValue(LinePaddingProperty); } | |
| set { SetValue(LinePaddingProperty, value); } | |
| } | |
| public static readonly DependencyProperty LinePaddingProperty = | |
| DependencyProperty.Register("LinePadding", typeof(double), typeof(SquereSizer), new PropertyMetadata(4d, OnLinePaddingPropertyChanged)); | |
| private static void OnLinePaddingPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) | |
| { | |
| var _this = (SquereSizer)d; | |
| _this.ApplyLineCenterOffset(); | |
| } | |
| void ApplyInnerLineCenterOffset() | |
| { | |
| var lineCenterOffset = LineWidth * 0.5; | |
| (Top_InnerLine_Transform.X, Top_InnerLine_Transform.Y) = (0, -lineCenterOffset); | |
| (Bottom_InnerLine_Transform.X, Bottom_InnerLine_Transform.Y) = (0, lineCenterOffset); | |
| (Left_InnerLine_Transform.X, Left_InnerLine_Transform.Y) = (-lineCenterOffset, 0); | |
| (Right_InnerLine_Transform.X, Right_InnerLine_Transform.Y) = (lineCenterOffset, 0); | |
| } | |
| void ApplyLineCenterOffset() | |
| { | |
| var lineCenterOffset = LinePadding + LineWidth * 0.5; | |
| (Top_OuterLine_Transform.X, Top_OuterLine_Transform.Y) = (0, -lineCenterOffset); | |
| (Bottom_OuterLine_Transform.X, Bottom_OuterLine_Transform.Y) = (0, lineCenterOffset); | |
| (Left_OuterLine_Transform.X, Left_OuterLine_Transform.Y) = (-lineCenterOffset, 0); | |
| (Right_OuterLine_Transform.X, Right_OuterLine_Transform.Y) = (lineCenterOffset, 0); | |
| } | |
| public Thickness ToHorizontalThickness(double value) => new Thickness(value, 0, value, 0); | |
| public Thickness ToVerticalThickness(double value) => new Thickness(0, value, 0, value); | |
| public Brush LineBackgroundBrush | |
| { | |
| get { return (Brush)GetValue(LineBackgroundBrushProperty); } | |
| set { SetValue(LineBackgroundBrushProperty, value); } | |
| } | |
| public static readonly DependencyProperty LineBackgroundBrushProperty = | |
| DependencyProperty.Register("LineBackgroundBrush", typeof(Brush), typeof(SquereSizer), new PropertyMetadata(new SolidColorBrush(Colors.Transparent))); | |
| public SquereSizerPositionBehavior PositionBehavior | |
| { | |
| get { return (SquereSizerPositionBehavior)GetValue(PositionBehaviorProperty); } | |
| set { SetValue(PositionBehaviorProperty, value); } | |
| } | |
| public static readonly DependencyProperty PositionBehaviorProperty = | |
| DependencyProperty.Register("PositionBehavior", typeof(SquereSizerPositionBehavior), typeof(SquereSizer), new PropertyMetadata(SquereSizerPositionBehavior.InsideArea)); | |
| public Point Position | |
| { | |
| get { return (Point)GetValue(PositionProperty); } | |
| set { SetValue(PositionProperty, value); } | |
| } | |
| public static readonly DependencyProperty PositionProperty = | |
| DependencyProperty.Register("Position", typeof(Point), typeof(SquereSizer), new PropertyMetadata(default(Point), OnPositionPropertyChanged)); | |
| private static void OnPositionPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) | |
| { | |
| var _this = (SquereSizer)d; | |
| _this.RootGrid_Transform.TranslateX = _this.Position.X; | |
| _this.RootGrid_Transform.TranslateY = _this.Position.Y; | |
| } | |
| public Point AreaTopLeft | |
| { | |
| get { return (Point)GetValue(AreaTopLeftProperty); } | |
| set { SetValue(AreaTopLeftProperty, value); } | |
| } | |
| public static readonly DependencyProperty AreaTopLeftProperty = | |
| DependencyProperty.Register("AreaTopLeft", typeof(Point), typeof(SquereSizer), new PropertyMetadata(new Point(0,0))); | |
| public Point AreaBottomRight | |
| { | |
| get { return (Point)GetValue(AreaBottomRightProperty); } | |
| set { SetValue(AreaBottomRightProperty, value); } | |
| } | |
| public static readonly DependencyProperty AreaBottomRightProperty = | |
| DependencyProperty.Register("AreaBottomRight", typeof(Point), typeof(SquereSizer), new PropertyMetadata(new Point(double.MaxValue, double.MaxValue))); | |
| public double ThumbWidth | |
| { | |
| get { return (double)GetValue(ThumbWidthProperty); } | |
| set { SetValue(ThumbWidthProperty, value); } | |
| } | |
| public static readonly DependencyProperty ThumbWidthProperty = | |
| DependencyProperty.Register("ThumbWidth", typeof(double), typeof(SquereSizer), new PropertyMetadata(32d, OnThumbWidthPropertyChanged)); | |
| private static void OnThumbWidthPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) | |
| { | |
| var _this = (SquereSizer)d; | |
| _this.ApplyThumbSizeFromThumbWidth(); | |
| } | |
| public Thickness ThumbMargin | |
| { | |
| get { return (Thickness)GetValue(ThumbMarginProperty); } | |
| set { SetValue(ThumbMarginProperty, value); } | |
| } | |
| public static readonly DependencyProperty ThumbMarginProperty = | |
| DependencyProperty.Register("ThumbMargin", typeof(Thickness), typeof(SquereSizer), new PropertyMetadata(new Thickness(2), OnThumbMarginPropertyChanged)); | |
| private static void OnThumbMarginPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) | |
| { | |
| var _this = (SquereSizer)d; | |
| _this.ApplyThumbSizeFromThumbWidth(); | |
| } | |
| void ApplyThumbSizeFromThumbWidth() | |
| { | |
| double halfWidth = ThumbWidth / 2 + ThumbMargin.Left; | |
| (TopLeft_Thumb_Transform.X, TopLeft_Thumb_Transform.Y) = (-halfWidth, -halfWidth); | |
| (TopRight_Thumb_Transform.X, TopRight_Thumb_Transform.Y) = (halfWidth, -halfWidth); | |
| (BottomLeft_Thumb_Transform.X, BottomLeft_Thumb_Transform.Y) = (-halfWidth, halfWidth); | |
| (BottomRight_Thumb_Transform.X, BottomRight_Thumb_Transform.Y) = (halfWidth, halfWidth); | |
| } | |
| public Brush ThumbStrokeBrush | |
| { | |
| get { return (Brush)GetValue(ThumbStrokeBrushProperty); } | |
| set { SetValue(ThumbStrokeBrushProperty, value); } | |
| } | |
| public static readonly DependencyProperty ThumbStrokeBrushProperty = | |
| DependencyProperty.Register("ThumbStrokeBrush", typeof(Brush), typeof(SquereSizer), new PropertyMetadata(null)); | |
| public Brush ThumbBackground | |
| { | |
| get { return (Brush)GetValue(ThumbBackgroundProperty); } | |
| set { SetValue(ThumbBackgroundProperty, value); } | |
| } | |
| public static readonly DependencyProperty ThumbBackgroundProperty = | |
| DependencyProperty.Register("ThumbBackground", typeof(Brush), typeof(SquereSizer), new PropertyMetadata(null)); | |
| Vector2 _dragStartPointerPosition; | |
| Vector2 _dragStartSize; | |
| Point _dragStartElementPosition; | |
| private void Thumb_PointerPressed(object sender, PointerRoutedEventArgs e) | |
| { | |
| var element = (FrameworkElement)sender; | |
| if (false == element.CapturePointer(e.Pointer)) { return; } | |
| var pt = e.GetCurrentPoint(PointerTarget); | |
| _dragStartPointerPosition = pt.Position.ToVector2(); | |
| _dragStartSize = new Size(RootGrid.ActualWidth, RootGrid.ActualHeight).ToVector2(); | |
| _dragStartElementPosition = Position; | |
| element.PointerMoved += Element_PointerMoved; | |
| element.PointerReleased += Element_PointerReleased; | |
| element.PointerCanceled += Element_PointerCanceled; | |
| element.PointerCaptureLost += Element_PointerCaptureLost; | |
| } | |
| FrameworkElement PointerTarget => this; | |
| private void Element_PointerMoved(object sender, PointerRoutedEventArgs e) | |
| { | |
| var element = (FrameworkElement)sender; | |
| var pt = e.GetCurrentPoint(PointerTarget); | |
| var currentPos = pt.Position.ToVector2(); | |
| var delta = _dragStartPointerPosition - currentPos; | |
| if (delta is not { X: 0 }) | |
| { | |
| if (element.HorizontalAlignment == HorizontalAlignment.Left) | |
| { | |
| var nextWidth = Math.Clamp(_dragStartSize.X + delta.X, MinWidth, MaxWidth); | |
| var nextX = (float)_dragStartElementPosition.X - delta.X; | |
| if (nextX < AreaTopLeft.X) | |
| { | |
| nextWidth = _dragStartSize.X + (_dragStartElementPosition.X - AreaTopLeft.X); | |
| nextX = (float)AreaTopLeft.X; | |
| } | |
| else if (nextWidth == MinWidth) | |
| { | |
| nextWidth = Width; | |
| nextX = (float)Position.X; | |
| } | |
| else if (nextX > AreaBottomRight.X) | |
| { | |
| nextWidth = nextWidth - (AreaBottomRight.X - nextX); | |
| nextX = (float)AreaBottomRight.X; | |
| } | |
| SetPositionRespectBehavior(new Vector2(nextX, (float)Position.Y)); | |
| Width = Math.Clamp(SizeCropToUnitWithRound(nextWidth, WidthChangeUnit), MinWidth, MaxWidth); | |
| } | |
| else if (element.HorizontalAlignment == HorizontalAlignment.Right) | |
| { | |
| var maxWidth = MaxWidth - Position.X; | |
| Width = Math.Clamp(SizeCropToUnitWithRound(_dragStartSize.X - delta.X, WidthChangeUnit), MinWidth, maxWidth); | |
| } | |
| } | |
| if (delta is not { Y: 0 }) | |
| { | |
| if (element.VerticalAlignment == VerticalAlignment.Top) | |
| { | |
| var nextHeight = Math.Clamp(_dragStartSize.Y + delta.Y, MinHeight, MaxHeight); | |
| float nextY = (float)_dragStartElementPosition.Y - delta.Y; | |
| if (nextY < AreaTopLeft.Y) | |
| { | |
| nextHeight = _dragStartSize.Y + (_dragStartElementPosition.Y - AreaTopLeft.Y); | |
| nextY = (float)AreaTopLeft.Y; | |
| } | |
| else if (nextHeight == MinHeight) | |
| { | |
| nextHeight = Height; | |
| nextY = (float)Position.Y; | |
| } | |
| else if (nextY > AreaBottomRight.Y) | |
| { | |
| nextHeight = nextHeight - (AreaBottomRight.Y - nextY); | |
| nextY = (float)AreaBottomRight.Y; | |
| } | |
| SetPositionRespectBehavior(new Vector2((float)Position.X, nextY)); | |
| Height = Math.Clamp(SizeCropToUnitWithRound(nextHeight, HeightChangeUnit), MinHeight, MaxHeight); ; | |
| } | |
| else if (element.VerticalAlignment == VerticalAlignment.Bottom) | |
| { | |
| var maxHeight = MaxHeight - Position.Y; | |
| Height = Math.Clamp(SizeCropToUnitWithRound(_dragStartSize.Y - delta.Y, HeightChangeUnit), MinHeight, maxHeight); | |
| } | |
| } | |
| } | |
| double SizeCropToUnitWithRound(double value, double unit) | |
| { | |
| if (unit <= 1) { return value; } | |
| var unitValue = value / unit; | |
| var roundValue = Math.Round(unitValue); | |
| return roundValue * unit; | |
| } | |
| private void Element_PointerReleased(object sender, PointerRoutedEventArgs e) | |
| { | |
| var pt = e.GetCurrentPoint(PointerTarget); | |
| var element = (FrameworkElement)sender; | |
| element.PointerMoved -= Element_PointerMoved; | |
| element.PointerReleased -= Element_PointerReleased; | |
| element.PointerCanceled -= Element_PointerCanceled; | |
| element.PointerCaptureLost -= Element_PointerCaptureLost; | |
| // ReleasePointerCaptureより後にイベントハンドリングを離すとMovedで初期位置が呼ばれる | |
| element.ReleasePointerCapture(e.Pointer); | |
| } | |
| private void Element_PointerCanceled(object sender, PointerRoutedEventArgs e) | |
| { | |
| var element = (FrameworkElement)sender; | |
| element.ReleasePointerCapture(e.Pointer); | |
| element.PointerMoved -= Element_PointerMoved; | |
| element.PointerReleased -= Element_PointerReleased; | |
| element.PointerCanceled -= Element_PointerCanceled; | |
| element.PointerCaptureLost -= Element_PointerCaptureLost; | |
| Position = _dragStartPointerPosition.ToPoint(); | |
| Width = _dragStartSize.X; | |
| Height = _dragStartSize.Y; | |
| } | |
| private void Element_PointerCaptureLost(object sender, PointerRoutedEventArgs e) | |
| { | |
| var element = (FrameworkElement)sender; | |
| element.ReleasePointerCapture(e.Pointer); | |
| element.PointerMoved -= Element_PointerMoved; | |
| element.PointerReleased -= Element_PointerReleased; | |
| element.PointerCanceled -= Element_PointerCanceled; | |
| element.PointerCaptureLost -= Element_PointerCaptureLost; | |
| Position = _dragStartPointerPosition.ToPoint(); | |
| Width = _dragStartSize.X; | |
| Height = _dragStartSize.Y; | |
| } | |
| Vector2 _positionChangeBorderToPointerPositionOffset; | |
| private void ChangePositionTrapBorder_PointerPressed(object sender, PointerRoutedEventArgs e) | |
| { | |
| var element = (FrameworkElement)sender; | |
| if (false == element.CapturePointer(e.Pointer)) { return; } | |
| var pt = e.GetCurrentPoint(PointerTarget); | |
| _dragStartPointerPosition = pt.Position.ToVector2(); | |
| _dragStartSize = new Size(RootGrid.ActualWidth, RootGrid.ActualHeight).ToVector2(); | |
| _positionChangeBorderToPointerPositionOffset = e.GetCurrentPoint(ChangePositionTrapBorder).Position.ToVector2(); | |
| element.PointerMoved += ChangePositionTrapBorder_PointerMoved; | |
| element.PointerReleased += ChangePositionTrapBorder_Released; | |
| element.PointerCanceled += ChangePositionTrapBorder_Canceled; | |
| element.PointerCaptureLost += ChangePositionTrapBorder_CaptureLost; | |
| } | |
| private void ChangePositionTrapBorder_PointerMoved(object sender, PointerRoutedEventArgs e) | |
| { | |
| var pt = e.GetCurrentPoint(PointerTarget); | |
| var currentPos = pt.Position.ToVector2(); | |
| var delta = _dragStartPointerPosition - currentPos; | |
| var nextPos = _dragStartPointerPosition - delta - _positionChangeBorderToPointerPositionOffset; | |
| SetPositionRespectBehavior(nextPos); | |
| } | |
| void SetPositionRespectBehavior(Vector2 nextPos) | |
| { | |
| double x = nextPos.X; | |
| double y = nextPos.Y; | |
| switch (PositionBehavior) | |
| { | |
| case SquereSizerPositionBehavior.Free: | |
| Position = nextPos.ToPoint(); | |
| break; | |
| case SquereSizerPositionBehavior.InsideArea: | |
| x = Math.Clamp(nextPos.X, AreaTopLeft.X, AreaBottomRight.X - Width); | |
| y = Math.Clamp(nextPos.Y, AreaTopLeft.Y, AreaBottomRight.Y - Height); | |
| break; | |
| case SquereSizerPositionBehavior.IntersectArea: | |
| x = Math.Clamp(nextPos.X, AreaTopLeft.X - Width, AreaBottomRight.X); | |
| y = Math.Clamp(nextPos.Y, AreaTopLeft.Y - Height, AreaBottomRight.Y); | |
| break; | |
| } | |
| Position = new Point(x, y); | |
| } | |
| private void ChangePositionTrapBorder_Released(object sender, PointerRoutedEventArgs e) | |
| { | |
| var pt = e.GetCurrentPoint(PointerTarget); | |
| var element = (FrameworkElement)sender; | |
| element.PointerMoved -= ChangePositionTrapBorder_PointerMoved; | |
| element.PointerReleased -= ChangePositionTrapBorder_Released; | |
| element.PointerCanceled -= ChangePositionTrapBorder_Canceled; | |
| element.PointerCaptureLost -= ChangePositionTrapBorder_CaptureLost; | |
| // ReleasePointerCaptureより後にイベントハンドリングを離すとMovedで初期位置が呼ばれる | |
| element.ReleasePointerCapture(e.Pointer); | |
| } | |
| private void ChangePositionTrapBorder_Canceled(object sender, PointerRoutedEventArgs e) | |
| { | |
| var element = (FrameworkElement)sender; | |
| element.ReleasePointerCapture(e.Pointer); | |
| element.PointerMoved -= ChangePositionTrapBorder_PointerMoved; | |
| element.PointerReleased -= ChangePositionTrapBorder_Released; | |
| element.PointerCanceled -= ChangePositionTrapBorder_Canceled; | |
| element.PointerCaptureLost -= ChangePositionTrapBorder_CaptureLost; | |
| } | |
| private void ChangePositionTrapBorder_CaptureLost(object sender, PointerRoutedEventArgs e) | |
| { | |
| var element = (FrameworkElement)sender; | |
| element.ReleasePointerCapture(e.Pointer); | |
| element.PointerMoved -= ChangePositionTrapBorder_PointerMoved; | |
| element.PointerReleased -= ChangePositionTrapBorder_Released; | |
| element.PointerCanceled -= ChangePositionTrapBorder_Canceled; | |
| element.PointerCaptureLost -= ChangePositionTrapBorder_CaptureLost; | |
| } | |
| bool Negate(bool value) => !value; | |
| public double WidthChangeUnit | |
| { | |
| get { return (double)GetValue(WidthChangeUnitProperty); } | |
| set { SetValue(WidthChangeUnitProperty, value); } | |
| } | |
| public static readonly DependencyProperty WidthChangeUnitProperty = | |
| DependencyProperty.Register("WidthChangeUnit", typeof(double), typeof(SquereSizer), new PropertyMetadata(1d)); | |
| public double HeightChangeUnit | |
| { | |
| get { return (double)GetValue(HeightChangeUnitProperty); } | |
| set { SetValue(HeightChangeUnitProperty, value); } | |
| } | |
| public static readonly DependencyProperty HeightChangeUnitProperty = | |
| DependencyProperty.Register("HeightChangeUnit", typeof(double), typeof(SquereSizer), new PropertyMetadata(1d)); | |
| public bool IsPositionChangeEnabled | |
| { | |
| get { return (bool)GetValue(IsPositionChangeEnabledProperty); } | |
| set { SetValue(IsPositionChangeEnabledProperty, value); } | |
| } | |
| public static readonly DependencyProperty IsPositionChangeEnabledProperty = | |
| DependencyProperty.Register("IsPositionChangeEnabled", typeof(bool), typeof(SquereSizer), new PropertyMetadata(true)); | |
| public bool IsTopLineChangeEnabled | |
| { | |
| get { return (bool)GetValue(IsTopLineChangeEnabledProperty); } | |
| set { SetValue(IsTopLineChangeEnabledProperty, value); } | |
| } | |
| public static readonly DependencyProperty IsTopLineChangeEnabledProperty = | |
| DependencyProperty.Register("IsTopLineChangeEnabled", typeof(bool), typeof(SquereSizer), new PropertyMetadata(true)); | |
| public bool IsRightLineChangeEnabled | |
| { | |
| get { return (bool)GetValue(IsRightLineChangeEnabledProperty); } | |
| set { SetValue(IsRightLineChangeEnabledProperty, value); } | |
| } | |
| public static readonly DependencyProperty IsRightLineChangeEnabledProperty = | |
| DependencyProperty.Register("IsRightLineChangeEnabled", typeof(bool), typeof(SquereSizer), new PropertyMetadata(true)); | |
| public bool IsBottomLineChangeEnabled | |
| { | |
| get { return (bool)GetValue(IsBottomLineChangeEnabledProperty); } | |
| set { SetValue(IsBottomLineChangeEnabledProperty, value); } | |
| } | |
| public static readonly DependencyProperty IsBottomLineChangeEnabledProperty = | |
| DependencyProperty.Register("IsBottomLineChangeEnabled", typeof(bool), typeof(SquereSizer), new PropertyMetadata(true)); | |
| public bool IsLeftLineChangeEnabled | |
| { | |
| get { return (bool)GetValue(IsLeftLineChangeEnabledProperty); } | |
| set { SetValue(IsLeftLineChangeEnabledProperty, value); } | |
| } | |
| public static readonly DependencyProperty IsLeftLineChangeEnabledProperty = | |
| DependencyProperty.Register("IsLeftLineChangeEnabled", typeof(bool), typeof(SquereSizer), new PropertyMetadata(true)); | |
| public bool IsTopLeftThumbChangeEnabled | |
| { | |
| get { return (bool)GetValue(IsTopLeftThumbChangeEnabledProperty); } | |
| set { SetValue(IsTopLeftThumbChangeEnabledProperty, value); } | |
| } | |
| public static readonly DependencyProperty IsTopLeftThumbChangeEnabledProperty = | |
| DependencyProperty.Register("IsTopLeftThumbChangeEnabled", typeof(bool), typeof(SquereSizer), new PropertyMetadata(true)); | |
| public bool IsTopRightThumbChangeEnabled | |
| { | |
| get { return (bool)GetValue(IsTopRightThumbChangeEnabledProperty); } | |
| set { SetValue(IsTopRightThumbChangeEnabledProperty, value); } | |
| } | |
| public static readonly DependencyProperty IsTopRightThumbChangeEnabledProperty = | |
| DependencyProperty.Register("IsTopRightThumbChangeEnabled", typeof(bool), typeof(SquereSizer), new PropertyMetadata(true)); | |
| public bool IsBottomLeftThumbChangeEnabled | |
| { | |
| get { return (bool)GetValue(IsBottomLeftThumbChangeEnabledProperty); } | |
| set { SetValue(IsBottomLeftThumbChangeEnabledProperty, value); } | |
| } | |
| public static readonly DependencyProperty IsBottomLeftThumbChangeEnabledProperty = | |
| DependencyProperty.Register("IsBottomLeftThumbChangeEnabled", typeof(bool), typeof(SquereSizer), new PropertyMetadata(true)); | |
| public bool IsBottomRightThumbChangeEnabled | |
| { | |
| get { return (bool)GetValue(IsBottomRightThumbChangeEnabledProperty); } | |
| set { SetValue(IsBottomRightThumbChangeEnabledProperty, value); } | |
| } | |
| public static readonly DependencyProperty IsBottomRightThumbChangeEnabledProperty = | |
| DependencyProperty.Register("IsBottomRightThumbChangeEnabled", typeof(bool), typeof(SquereSizer), new PropertyMetadata(true)); | |
| } | |
| public enum SquereSizerPositionBehavior | |
| { | |
| Free, | |
| InsideArea, | |
| IntersectArea, | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment