From 2248a4b5a8d52def240b9485076c93215550266d Mon Sep 17 00:00:00 2001 From: donandren Date: Sat, 5 Dec 2015 21:09:53 +0200 Subject: [PATCH 01/12] no need for layout scale to be taken into account because touch events are already scaled --- src/iOS/Perspex.iOS/PerspexView.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/iOS/Perspex.iOS/PerspexView.cs b/src/iOS/Perspex.iOS/PerspexView.cs index 4adfb98790..5a87b38e96 100644 --- a/src/iOS/Perspex.iOS/PerspexView.cs +++ b/src/iOS/Perspex.iOS/PerspexView.cs @@ -168,14 +168,11 @@ namespace Perspex.iOS RawMouseEventType.Move, location, InputModifiers.LeftMouseButton)); else { - double x = location.X - _touchLastPoint.X; - double y = location.Y - _touchLastPoint.Y; + //magic number based on test - correction of 0.02 is working perfect double correction = 0.02; - var scale = PerspexLocator.Current.GetService().RenderScalingFactor; - scale = 1; Input?.Invoke(new RawMouseWheelEventArgs(PerspexAppDelegate.MouseDevice, (uint)touch.Timestamp, - _inputRoot, location, new Vector(x * correction / scale, y * correction / scale), InputModifiers.LeftMouseButton)); + _inputRoot, location, (location - _touchLastPoint)* correction, InputModifiers.LeftMouseButton)); } _touchLastPoint = location; } From 05da19937f259dd3151fa3cb49b685bc2cab150d Mon Sep 17 00:00:00 2001 From: donandren Date: Wed, 9 Dec 2015 20:34:15 +0200 Subject: [PATCH 02/12] Path properly parse Arc implemented - issue #354 --- .../Media/PathMarkupParser.cs | 39 +++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/src/Perspex.SceneGraph/Media/PathMarkupParser.cs b/src/Perspex.SceneGraph/Media/PathMarkupParser.cs index 0caa53dc7c..17539c924b 100644 --- a/src/Perspex.SceneGraph/Media/PathMarkupParser.cs +++ b/src/Perspex.SceneGraph/Media/PathMarkupParser.cs @@ -28,6 +28,8 @@ namespace Perspex.Media { 'v', Command.VerticalLineRelative }, { 'C', Command.CubicBezierCurve }, { 'c', Command.CubicBezierCurveRelative }, + { 'A', Command.Arc }, + { 'a', Command.Arc }, { 'Z', Command.Close }, { 'z', Command.Close }, }; @@ -64,6 +66,7 @@ namespace Perspex.Media VerticalLineRelative, CubicBezierCurve, CubicBezierCurveRelative, + Arc, Close, Eof, } @@ -98,8 +101,8 @@ namespace Perspex.Media _context.EndFigure(false); } - point = command == Command.Move ? - ReadPoint(reader) : + point = command == Command.Move ? + ReadPoint(reader) : ReadRelativePoint(reader, point); _context.BeginFigure(point, true); @@ -144,6 +147,22 @@ namespace Perspex.Media _context.CubicBezierTo(point1, point2, point); break; } + case Command.Arc: + { + //example: A10,10 0 0,0 10,20 + //format - size rotationAngle isLargeArcFlag sweepDirectionFlag endPoint + Size size = ReadSize(reader); + ReadSeparator(reader); + double rotationAngle = ReadDouble(reader); + ReadSeparator(reader); + bool isLargeArc = ReadBool(reader); + ReadSeparator(reader); + SweepDirection sweepDirection = ReadBool(reader) ? SweepDirection.Clockwise : SweepDirection.CounterClockwise; + point = ReadPoint(reader); + + _context.ArcTo(point, size, rotationAngle, isLargeArc, sweepDirection); + break; + } case Command.Close: _context.EndFigure(true); @@ -244,6 +263,20 @@ namespace Perspex.Media return new Point(x, y); } + private static Size ReadSize(StringReader reader) + { + ReadWhitespace(reader); + double x = ReadDouble(reader); + ReadSeparator(reader); + double y = ReadDouble(reader); + return new Size(x, y); + } + + private static bool ReadBool(StringReader reader) + { + return ReadDouble(reader) != 0; + } + private static Point ReadRelativePoint(StringReader reader, Point lastPoint) { ReadWhitespace(reader); @@ -302,4 +335,4 @@ namespace Perspex.Media } } } -} +} \ No newline at end of file From 8f24ccf44181db5617048cc0779cf284f0349a6e Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 11 Dec 2015 04:11:57 +0300 Subject: [PATCH 03/12] Added Window::HasSystemDecorations property --- .../Platform/SkiaPlatform/WindowImpl.cs | 3 ++ src/Gtk/Perspex.Gtk/WindowImpl.cs | 2 + src/Perspex.Controls/Platform/IWindowImpl.cs | 5 +++ .../Platform/PlatformManager.cs | 1 + src/Perspex.Controls/Window.cs | 18 ++++++++ .../Perspex.Win32/Interop/UnmanagedMethods.cs | 3 ++ src/Windows/Perspex.Win32/WindowImpl.cs | 43 +++++++++++++++++++ src/iOS/Perspex.iOS/PerspexView.cs | 5 +++ 8 files changed, 80 insertions(+) diff --git a/src/Android/Perspex.Android/Platform/SkiaPlatform/WindowImpl.cs b/src/Android/Perspex.Android/Platform/SkiaPlatform/WindowImpl.cs index b7125a56ed..09aa7a165c 100644 --- a/src/Android/Perspex.Android/Platform/SkiaPlatform/WindowImpl.cs +++ b/src/Android/Perspex.Android/Platform/SkiaPlatform/WindowImpl.cs @@ -94,6 +94,9 @@ namespace Perspex.Android.Platform.SkiaPlatform this.Visibility = ViewStates.Invisible; } + public void SetSystemDecorations(bool enabled) + { + } public void Invalidate(Rect rect) { if (Holder?.Surface?.IsValid == true) base.Invalidate(); diff --git a/src/Gtk/Perspex.Gtk/WindowImpl.cs b/src/Gtk/Perspex.Gtk/WindowImpl.cs index 64b1beb779..afeaaf9ff0 100644 --- a/src/Gtk/Perspex.Gtk/WindowImpl.cs +++ b/src/Gtk/Perspex.Gtk/WindowImpl.cs @@ -170,6 +170,8 @@ namespace Perspex.Gtk return Disposable.Empty; } + public void SetSystemDecorations(bool enabled) => Decorated = enabled; + void ITopLevelImpl.Activate() { Activate(); diff --git a/src/Perspex.Controls/Platform/IWindowImpl.cs b/src/Perspex.Controls/Platform/IWindowImpl.cs index f8bd6588cd..e27d94b41e 100644 --- a/src/Perspex.Controls/Platform/IWindowImpl.cs +++ b/src/Perspex.Controls/Platform/IWindowImpl.cs @@ -33,5 +33,10 @@ namespace Perspex.Platform /// Hides the window. /// void Hide(); + + /// + /// Enables of disables system window decorations (title bar, buttons, etc) + /// + void SetSystemDecorations(bool enabled); } } diff --git a/src/Perspex.Controls/Platform/PlatformManager.cs b/src/Perspex.Controls/Platform/PlatformManager.cs index 1e13b926c0..735b810d91 100644 --- a/src/Perspex.Controls/Platform/PlatformManager.cs +++ b/src/Perspex.Controls/Platform/PlatformManager.cs @@ -178,6 +178,7 @@ namespace Perspex.Controls.Platform public IDisposable ShowDialog() => _window.ShowDialog(); public void Hide() => _popup.Hide(); + public void SetSystemDecorations(bool enabled) => _window.SetSystemDecorations(enabled); } public static IWindowImpl CreateWindow() diff --git a/src/Perspex.Controls/Window.cs b/src/Perspex.Controls/Window.cs index 1e7855e204..7798bde1f4 100644 --- a/src/Perspex.Controls/Window.cs +++ b/src/Perspex.Controls/Window.cs @@ -49,6 +49,12 @@ namespace Perspex.Controls public static readonly PerspexProperty SizeToContentProperty = PerspexProperty.Register(nameof(SizeToContent)); + /// + /// Enables of disables system window decorations (title bar, buttons, etc) + /// + public static readonly PerspexProperty HasSystemDecorationsProperty = + PerspexProperty.Register(nameof(HasSystemDecorations), true); + /// /// Defines the property. /// @@ -66,6 +72,8 @@ namespace Perspex.Controls { BackgroundProperty.OverrideDefaultValue(typeof(Window), Brushes.White); TitleProperty.Changed.AddClassHandler((s, e) => s.PlatformImpl.SetTitle((string)e.NewValue)); + HasSystemDecorationsProperty.Changed.AddClassHandler( + (s, e) => s.PlatformImpl.SetSystemDecorations((bool) e.NewValue)); } /// @@ -114,6 +122,16 @@ namespace Perspex.Controls set { SetValue(TitleProperty, value); } } + /// + /// Enables of disables system window decorations (title bar, buttons, etc) + /// + /// + public bool HasSystemDecorations + { + get { return GetValue(HasSystemDecorationsProperty); } + set { SetValue(HasSystemDecorationsProperty, value); } + } + /// Type IStyleable.StyleKey => typeof(Window); diff --git a/src/Windows/Perspex.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Perspex.Win32/Interop/UnmanagedMethods.cs index 5e281b5678..b19d771512 100644 --- a/src/Windows/Perspex.Win32/Interop/UnmanagedMethods.cs +++ b/src/Windows/Perspex.Win32/Interop/UnmanagedMethods.cs @@ -571,6 +571,9 @@ namespace Perspex.Win32.Interop [DllImport("user32.dll", SetLastError = true)] public static extern uint GetWindowLong(IntPtr hWnd, int nIndex); + [DllImport("user32.dll", SetLastError = true)] + public static extern uint SetWindowLong(IntPtr hWnd, int nIndex, uint value); + [DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect); diff --git a/src/Windows/Perspex.Win32/WindowImpl.cs b/src/Windows/Perspex.Win32/WindowImpl.cs index 3ae9dc26cb..03fcd7cc6d 100644 --- a/src/Windows/Perspex.Win32/WindowImpl.cs +++ b/src/Windows/Perspex.Win32/WindowImpl.cs @@ -37,6 +37,8 @@ namespace Perspex.Win32 private bool _isActive; + private bool _decorated = true; + public WindowImpl() { CreateWindow(); @@ -145,6 +147,47 @@ namespace Perspex.Win32 UnmanagedMethods.ShowWindow(_hwnd, UnmanagedMethods.ShowWindowCommand.Hide); } + public void SetSystemDecorations(bool value) + { + if (value == _decorated) + return; + var style = (UnmanagedMethods.WindowStyles) UnmanagedMethods.GetWindowLong(_hwnd, -16); + style |= UnmanagedMethods.WindowStyles.WS_OVERLAPPEDWINDOW; + if (!value) + style ^= UnmanagedMethods.WindowStyles.WS_OVERLAPPEDWINDOW; + + UnmanagedMethods.RECT windowRect; + + UnmanagedMethods.GetWindowRect(_hwnd, out windowRect); + Rect newRect; + var oldThickness = BorderThickness; + + UnmanagedMethods.SetWindowLong(_hwnd, -16, (uint) style); + if (value) + { + var thickness = BorderThickness; + newRect = new Rect( + windowRect.left - thickness.Left, + windowRect.top - thickness.Top, + (windowRect.right - windowRect.left) + (thickness.Left + thickness.Right), + (windowRect.bottom - windowRect.top) + (thickness.Top + thickness.Bottom)); + } + else + newRect = new Rect( + windowRect.left + oldThickness.Left, + windowRect.top + oldThickness.Top, + (windowRect.right - windowRect.left) - (oldThickness.Left + oldThickness.Right), + (windowRect.bottom - windowRect.top) - (oldThickness.Top + oldThickness.Bottom)); + UnmanagedMethods.SetWindowPos(_hwnd, IntPtr.Zero, (int) newRect.X, (int) newRect.Y, (int) newRect.Width, + (int) newRect.Height, + UnmanagedMethods.SetWindowPosFlags.SWP_NOZORDER | UnmanagedMethods.SetWindowPosFlags.SWP_NOACTIVATE); + + + _decorated = value; + + + } + public void Invalidate(Rect rect) { var r = new UnmanagedMethods.RECT diff --git a/src/iOS/Perspex.iOS/PerspexView.cs b/src/iOS/Perspex.iOS/PerspexView.cs index 4adfb98790..52fe69d8d1 100644 --- a/src/iOS/Perspex.iOS/PerspexView.cs +++ b/src/iOS/Perspex.iOS/PerspexView.cs @@ -124,6 +124,11 @@ namespace Perspex.iOS //Not supported } + public void SetSystemDecorations(bool enabled) + { + //Not supported + } + public override void TouchesEnded(NSSet touches, UIEvent evt) { var touch = touches.AnyObject as UITouch; From 0b0875970c5dba043761b3267ed8da577472d8b0 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 11 Dec 2015 05:43:58 +0300 Subject: [PATCH 04/12] Added TopLevel::BeginMoveDrag() --- .../Perspex.Android/Platform/SkiaPlatform/WindowImpl.cs | 5 +++++ src/Gtk/Perspex.Gtk/WindowImpl.cs | 8 ++++++++ src/Perspex.Controls/Platform/ITopLevelImpl.cs | 5 +++++ src/Perspex.Controls/Platform/PlatformManager.cs | 1 + src/Perspex.Controls/TopLevel.cs | 5 +++++ src/Windows/Perspex.Win32/WindowImpl.cs | 6 ++++++ src/iOS/Perspex.iOS/PerspexView.cs | 5 +++++ 7 files changed, 35 insertions(+) diff --git a/src/Android/Perspex.Android/Platform/SkiaPlatform/WindowImpl.cs b/src/Android/Perspex.Android/Platform/SkiaPlatform/WindowImpl.cs index 09aa7a165c..1697295198 100644 --- a/src/Android/Perspex.Android/Platform/SkiaPlatform/WindowImpl.cs +++ b/src/Android/Perspex.Android/Platform/SkiaPlatform/WindowImpl.cs @@ -126,6 +126,11 @@ namespace Perspex.Android.Platform.SkiaPlatform this.Visibility = ViewStates.Visible; } + public void BeginMoveDrag() + { + //Not supported + } + public IDisposable ShowDialog() { throw new NotImplementedException(); diff --git a/src/Gtk/Perspex.Gtk/WindowImpl.cs b/src/Gtk/Perspex.Gtk/WindowImpl.cs index afeaaf9ff0..735150f9b2 100644 --- a/src/Gtk/Perspex.Gtk/WindowImpl.cs +++ b/src/Gtk/Perspex.Gtk/WindowImpl.cs @@ -162,6 +162,14 @@ namespace Perspex.Gtk GdkWindow.Cursor = cursor != null ? new Gdk.Cursor(cursor.Handle) : DefaultCursor; } + public void BeginMoveDrag() + { + int x, y; + ModifierType mod; + Screen.RootWindow.GetPointer(out x, out y, out mod); + BeginMoveDrag(0, x, y, 0); + } + public IDisposable ShowDialog() { Modal = true; diff --git a/src/Perspex.Controls/Platform/ITopLevelImpl.cs b/src/Perspex.Controls/Platform/ITopLevelImpl.cs index f826ec5990..ade7aab3bd 100644 --- a/src/Perspex.Controls/Platform/ITopLevelImpl.cs +++ b/src/Perspex.Controls/Platform/ITopLevelImpl.cs @@ -88,5 +88,10 @@ namespace Perspex.Platform /// Shows the toplevel. /// void Show(); + + /// + /// Starts moving a window with left button being held. Should be called from left mouse button press event handler + /// + void BeginMoveDrag(); } } diff --git a/src/Perspex.Controls/Platform/PlatformManager.cs b/src/Perspex.Controls/Platform/PlatformManager.cs index 735b810d91..1e7b5cc755 100644 --- a/src/Perspex.Controls/Platform/PlatformManager.cs +++ b/src/Perspex.Controls/Platform/PlatformManager.cs @@ -174,6 +174,7 @@ namespace Perspex.Controls.Platform public void SetTitle(string title) => _window.SetTitle(title); public void Show() => _tl.Show(); + public void BeginMoveDrag() => _tl.BeginMoveDrag(); public IDisposable ShowDialog() => _window.ShowDialog(); diff --git a/src/Perspex.Controls/TopLevel.cs b/src/Perspex.Controls/TopLevel.cs index ca84f67de1..dffedefbe2 100644 --- a/src/Perspex.Controls/TopLevel.cs +++ b/src/Perspex.Controls/TopLevel.cs @@ -364,5 +364,10 @@ namespace Perspex.Controls { _renderQueueManager?.InvalidateRender(this); } + + /// + /// Starts moving a window with left button being held. Should be called from left mouse button press event handler + /// + public void BeginMoveDrag() => PlatformImpl.BeginMoveDrag(); } } diff --git a/src/Windows/Perspex.Win32/WindowImpl.cs b/src/Windows/Perspex.Win32/WindowImpl.cs index 03fcd7cc6d..063be91873 100644 --- a/src/Windows/Perspex.Win32/WindowImpl.cs +++ b/src/Windows/Perspex.Win32/WindowImpl.cs @@ -223,6 +223,12 @@ namespace Perspex.Win32 UnmanagedMethods.ShowWindow(_hwnd, UnmanagedMethods.ShowWindowCommand.Normal); } + public void BeginMoveDrag() + { + UnmanagedMethods.DefWindowProc(_hwnd, (int) UnmanagedMethods.WindowsMessage.WM_NCLBUTTONDOWN, + new IntPtr(2), IntPtr.Zero); + } + public virtual IDisposable ShowDialog() { var disabled = s_instances.Where(x => x != this && x.IsEnabled).ToList(); diff --git a/src/iOS/Perspex.iOS/PerspexView.cs b/src/iOS/Perspex.iOS/PerspexView.cs index 52fe69d8d1..1ccf78330f 100644 --- a/src/iOS/Perspex.iOS/PerspexView.cs +++ b/src/iOS/Perspex.iOS/PerspexView.cs @@ -107,6 +107,11 @@ namespace Perspex.iOS _keyboardHelper.ActivateAutoShowKeybord(); } + public void BeginMoveDrag() + { + //Not supported + } + public Size MaxClientSize => Bounds.Size.ToPerspex(); public void SetTitle(string title) { From 7b56292655cd971580f4de77dd6e679178890769 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 11 Dec 2015 05:46:49 +0300 Subject: [PATCH 05/12] GtkWindow::BeginMoveDrag should receive Button1 as the first argument --- src/Gtk/Perspex.Gtk/WindowImpl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Gtk/Perspex.Gtk/WindowImpl.cs b/src/Gtk/Perspex.Gtk/WindowImpl.cs index 735150f9b2..67d075add8 100644 --- a/src/Gtk/Perspex.Gtk/WindowImpl.cs +++ b/src/Gtk/Perspex.Gtk/WindowImpl.cs @@ -167,7 +167,7 @@ namespace Perspex.Gtk int x, y; ModifierType mod; Screen.RootWindow.GetPointer(out x, out y, out mod); - BeginMoveDrag(0, x, y, 0); + BeginMoveDrag(1, x, y, 0); } public IDisposable ShowDialog() From 53b909282660a81c5dd7c8d983f385b0159280ac Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Sat, 12 Dec 2015 07:09:41 +0300 Subject: [PATCH 06/12] Added cursor type converter --- .../Context/PerspexWiringContext.cs | 1 + .../Converters/CursorTypeConverter.cs | 36 +++++++++++++++++++ .../Perspex.Markup.Xaml.csproj | 1 + 3 files changed, 38 insertions(+) create mode 100644 src/Markup/Perspex.Markup.Xaml/Converters/CursorTypeConverter.cs diff --git a/src/Markup/Perspex.Markup.Xaml/Context/PerspexWiringContext.cs b/src/Markup/Perspex.Markup.Xaml/Context/PerspexWiringContext.cs index 89203022a9..ab16826dc6 100644 --- a/src/Markup/Perspex.Markup.Xaml/Context/PerspexWiringContext.cs +++ b/src/Markup/Perspex.Markup.Xaml/Context/PerspexWiringContext.cs @@ -107,6 +107,7 @@ namespace Perspex.Markup.Xaml.Context new TypeConverterRegistration(typeof(Thickness), new ThicknessTypeConverter()), new TypeConverterRegistration(typeof(TimeSpan), new TimeSpanTypeConverter()), new TypeConverterRegistration(typeof(Uri), new UriTypeConverter()), + new TypeConverterRegistration(typeof(Cursor), new CursorTypeConverter()) }; typeConverterProvider.AddAll(converters); diff --git a/src/Markup/Perspex.Markup.Xaml/Converters/CursorTypeConverter.cs b/src/Markup/Perspex.Markup.Xaml/Converters/CursorTypeConverter.cs new file mode 100644 index 0000000000..2310d563c5 --- /dev/null +++ b/src/Markup/Perspex.Markup.Xaml/Converters/CursorTypeConverter.cs @@ -0,0 +1,36 @@ +// Copyright (c) The Perspex Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using OmniXaml.TypeConversion; +using Perspex.Input; +using Perspex.Media.Imaging; +using Perspex.Platform; + +namespace Perspex.Markup.Xaml.Converters +{ + public class CursorTypeConverter : ITypeConverter + { + public bool CanConvertFrom(IXamlTypeConverterContext context, Type sourceType) + { + return sourceType == typeof(string); + } + + public bool CanConvertTo(IXamlTypeConverterContext context, Type destinationType) + { + return false; + } + + public object ConvertFrom(IXamlTypeConverterContext context, CultureInfo culture, object value) + { + var cursor = (StandardCursorType)Enum.Parse(typeof (StandardCursorType), ((string) value).Trim(), true); + return new Cursor(cursor); + } + + public object ConvertTo(IXamlTypeConverterContext context, CultureInfo culture, object value, Type destinationType) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj b/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj index 9b8cb35162..484363cd85 100644 --- a/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj +++ b/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj @@ -39,6 +39,7 @@ Properties\SharedAssemblyInfo.cs + From ec2a319049c8f033fc38c4122f1778b58dd52aee Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Sat, 12 Dec 2015 07:38:29 +0300 Subject: [PATCH 07/12] Implemented BeginResizeDrag --- .../Platform/SkiaPlatform/WindowImpl.cs | 6 ++++ src/Gtk/Perspex.Gtk/WindowImpl.cs | 9 ++++++ src/Perspex.Controls/Perspex.Controls.csproj | 1 + .../Platform/ITopLevelImpl.cs | 9 +++++- .../Platform/PlatformManager.cs | 1 + src/Perspex.Controls/TopLevel.cs | 6 ++++ src/Perspex.Controls/WindowEdge.cs | 17 +++++++++++ .../Perspex.Win32/Interop/UnmanagedMethods.cs | 28 +++++++++++++++++++ src/Windows/Perspex.Win32/WindowImpl.cs | 20 ++++++++++++- src/iOS/Perspex.iOS/PerspexView.cs | 6 ++++ 10 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 src/Perspex.Controls/WindowEdge.cs diff --git a/src/Android/Perspex.Android/Platform/SkiaPlatform/WindowImpl.cs b/src/Android/Perspex.Android/Platform/SkiaPlatform/WindowImpl.cs index 1697295198..14bd084a37 100644 --- a/src/Android/Perspex.Android/Platform/SkiaPlatform/WindowImpl.cs +++ b/src/Android/Perspex.Android/Platform/SkiaPlatform/WindowImpl.cs @@ -9,6 +9,7 @@ using Perspex.Input.Raw; using Perspex.Platform; using Perspex.Skia.Android; using System; +using Perspex.Controls; namespace Perspex.Android.Platform.SkiaPlatform { @@ -131,6 +132,11 @@ namespace Perspex.Android.Platform.SkiaPlatform //Not supported } + public void BeginResizeDrag(WindowEdge edge) + { + //Not supported + } + public IDisposable ShowDialog() { throw new NotImplementedException(); diff --git a/src/Gtk/Perspex.Gtk/WindowImpl.cs b/src/Gtk/Perspex.Gtk/WindowImpl.cs index 67d075add8..01054ae50b 100644 --- a/src/Gtk/Perspex.Gtk/WindowImpl.cs +++ b/src/Gtk/Perspex.Gtk/WindowImpl.cs @@ -11,6 +11,7 @@ using Perspex.Platform; using Perspex.Input; using Perspex.Threading; using Action = System.Action; +using WindowEdge = Perspex.Controls.WindowEdge; namespace Perspex.Gtk { @@ -170,6 +171,14 @@ namespace Perspex.Gtk BeginMoveDrag(1, x, y, 0); } + public void BeginResizeDrag(WindowEdge edge) + { + int x, y; + ModifierType mod; + Screen.RootWindow.GetPointer(out x, out y, out mod); + BeginResizeDrag((Gdk.WindowEdge) (int) edge, 1, x, y, 0); + } + public IDisposable ShowDialog() { Modal = true; diff --git a/src/Perspex.Controls/Perspex.Controls.csproj b/src/Perspex.Controls/Perspex.Controls.csproj index f9a4a3ad84..5a8557da6b 100644 --- a/src/Perspex.Controls/Perspex.Controls.csproj +++ b/src/Perspex.Controls/Perspex.Controls.csproj @@ -171,6 +171,7 @@ + diff --git a/src/Perspex.Controls/Platform/ITopLevelImpl.cs b/src/Perspex.Controls/Platform/ITopLevelImpl.cs index ade7aab3bd..0a11566c5a 100644 --- a/src/Perspex.Controls/Platform/ITopLevelImpl.cs +++ b/src/Perspex.Controls/Platform/ITopLevelImpl.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See licence.md file in the project root for full license information. using System; +using Perspex.Controls; using Perspex.Input; using Perspex.Input.Raw; @@ -90,8 +91,14 @@ namespace Perspex.Platform void Show(); /// - /// Starts moving a window with left button being held. Should be called from left mouse button press event handler + /// Starts moving a window with left button being held. Should be called from left mouse button press event handler. /// void BeginMoveDrag(); + + /// + /// Starts resizing a window. This function is used if an application has window resizing controls. + /// Should be called from left mouse button press event handler + /// + void BeginResizeDrag(WindowEdge edge); } } diff --git a/src/Perspex.Controls/Platform/PlatformManager.cs b/src/Perspex.Controls/Platform/PlatformManager.cs index 1e7b5cc755..fc582ab45d 100644 --- a/src/Perspex.Controls/Platform/PlatformManager.cs +++ b/src/Perspex.Controls/Platform/PlatformManager.cs @@ -175,6 +175,7 @@ namespace Perspex.Controls.Platform public void Show() => _tl.Show(); public void BeginMoveDrag() => _tl.BeginMoveDrag(); + public void BeginResizeDrag(WindowEdge edge) => _tl.BeginResizeDrag(edge); public IDisposable ShowDialog() => _window.ShowDialog(); diff --git a/src/Perspex.Controls/TopLevel.cs b/src/Perspex.Controls/TopLevel.cs index dffedefbe2..12311df1c9 100644 --- a/src/Perspex.Controls/TopLevel.cs +++ b/src/Perspex.Controls/TopLevel.cs @@ -369,5 +369,11 @@ namespace Perspex.Controls /// Starts moving a window with left button being held. Should be called from left mouse button press event handler /// public void BeginMoveDrag() => PlatformImpl.BeginMoveDrag(); + + /// + /// Starts resizing a window. This function is used if an application has window resizing controls. + /// Should be called from left mouse button press event handler + /// + public void BeginResizeDrag(WindowEdge edge) => PlatformImpl.BeginResizeDrag(edge); } } diff --git a/src/Perspex.Controls/WindowEdge.cs b/src/Perspex.Controls/WindowEdge.cs new file mode 100644 index 0000000000..356f882899 --- /dev/null +++ b/src/Perspex.Controls/WindowEdge.cs @@ -0,0 +1,17 @@ +namespace Perspex.Controls +{ + + public enum WindowEdge + { + //Please don't reorder stuff here, I was lazy to write proper conversion code + //so the order of values is matching one from GTK + NorthWest = 0, + North, + NorthEast, + West, + East, + SouthWest, + South, + SouthEast, + } +} \ No newline at end of file diff --git a/src/Windows/Perspex.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Perspex.Win32/Interop/UnmanagedMethods.cs index b19d771512..02aefb4106 100644 --- a/src/Windows/Perspex.Win32/Interop/UnmanagedMethods.cs +++ b/src/Windows/Perspex.Win32/Interop/UnmanagedMethods.cs @@ -217,6 +217,34 @@ namespace Perspex.Win32.Interop WA_CLICKACTIVE, } + public enum HitTestValues + { + HTERROR = -2, + HTTRANSPARENT = -1, + HTNOWHERE = 0, + HTCLIENT = 1, + HTCAPTION = 2, + HTSYSMENU = 3, + HTGROWBOX = 4, + HTMENU = 5, + HTHSCROLL = 6, + HTVSCROLL = 7, + HTMINBUTTON = 8, + HTMAXBUTTON = 9, + HTLEFT = 10, + HTRIGHT = 11, + HTTOP = 12, + HTTOPLEFT = 13, + HTTOPRIGHT = 14, + HTBOTTOM = 15, + HTBOTTOMLEFT = 16, + HTBOTTOMRIGHT = 17, + HTBORDER = 18, + HTOBJECT = 19, + HTCLOSE = 20, + HTHELP = 21 + } + [Flags] public enum WindowStyles : uint { diff --git a/src/Windows/Perspex.Win32/WindowImpl.cs b/src/Windows/Perspex.Win32/WindowImpl.cs index 063be91873..ca1a2ae9c6 100644 --- a/src/Windows/Perspex.Win32/WindowImpl.cs +++ b/src/Windows/Perspex.Win32/WindowImpl.cs @@ -226,7 +226,25 @@ namespace Perspex.Win32 public void BeginMoveDrag() { UnmanagedMethods.DefWindowProc(_hwnd, (int) UnmanagedMethods.WindowsMessage.WM_NCLBUTTONDOWN, - new IntPtr(2), IntPtr.Zero); + new IntPtr((int)UnmanagedMethods.HitTestValues.HTCAPTION), IntPtr.Zero); + } + + static readonly Dictionary EdgeDic = new Dictionary + { + {WindowEdge.East, UnmanagedMethods.HitTestValues.HTRIGHT}, + {WindowEdge.North, UnmanagedMethods.HitTestValues.HTTOP }, + {WindowEdge.NorthEast, UnmanagedMethods.HitTestValues.HTTOPRIGHT }, + {WindowEdge.NorthWest, UnmanagedMethods.HitTestValues.HTTOPLEFT }, + {WindowEdge.South, UnmanagedMethods.HitTestValues.HTBOTTOM }, + {WindowEdge.SouthEast, UnmanagedMethods.HitTestValues.HTBOTTOMRIGHT }, + {WindowEdge.SouthWest, UnmanagedMethods.HitTestValues.HTBOTTOMLEFT }, + {WindowEdge.West, UnmanagedMethods.HitTestValues.HTLEFT} + }; + + public void BeginResizeDrag(WindowEdge edge) + { + UnmanagedMethods.DefWindowProc(_hwnd, (int) UnmanagedMethods.WindowsMessage.WM_NCLBUTTONDOWN, + new IntPtr((int) EdgeDic[edge]), IntPtr.Zero); } public virtual IDisposable ShowDialog() diff --git a/src/iOS/Perspex.iOS/PerspexView.cs b/src/iOS/Perspex.iOS/PerspexView.cs index 1ccf78330f..92b2fac730 100644 --- a/src/iOS/Perspex.iOS/PerspexView.cs +++ b/src/iOS/Perspex.iOS/PerspexView.cs @@ -16,6 +16,7 @@ using Perspex.Skia.iOS; using UIKit; using Perspex.iOS.Specific; using ObjCRuntime; +using Perspex.Controls; namespace Perspex.iOS { @@ -112,6 +113,11 @@ namespace Perspex.iOS //Not supported } + public void BeginResizeDrag(WindowEdge edge) + { + //Not supported + } + public Size MaxClientSize => Bounds.Size.ToPerspex(); public void SetTitle(string title) { From f85d68d58047726587a85b0ba513b88a71fbb0b2 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Sun, 13 Dec 2015 02:23:16 +0300 Subject: [PATCH 08/12] Added some sizing cursors --- src/Gtk/Perspex.Gtk/CursorFactory.cs | 32 ++++++++++------- src/Perspex.Input/Cursors.cs | 10 +++++- src/Windows/Perspex.Win32/CursorFactory.cs | 40 +++++++++++++--------- 3 files changed, 53 insertions(+), 29 deletions(-) diff --git a/src/Gtk/Perspex.Gtk/CursorFactory.cs b/src/Gtk/Perspex.Gtk/CursorFactory.cs index 80e6b7b1e6..6a250024bf 100644 --- a/src/Gtk/Perspex.Gtk/CursorFactory.cs +++ b/src/Gtk/Perspex.Gtk/CursorFactory.cs @@ -21,20 +21,28 @@ namespace Perspex.Gtk private static readonly Dictionary CursorTypeMapping = new Dictionary { - { StandardCursorType.AppStarting, CursorType.Watch }, - { StandardCursorType.Arrow, CursorType.LeftPtr }, - { StandardCursorType.Cross, CursorType.Cross }, - { StandardCursorType.Hand, CursorType.Hand1 }, - { StandardCursorType.Ibeam, CursorType.Xterm }, - { StandardCursorType.No, Gtk.Stock.Cancel}, - { StandardCursorType.SizeAll, CursorType.Sizing }, + {StandardCursorType.AppStarting, CursorType.Watch}, + {StandardCursorType.Arrow, CursorType.LeftPtr}, + {StandardCursorType.Cross, CursorType.Cross}, + {StandardCursorType.Hand, CursorType.Hand1}, + {StandardCursorType.Ibeam, CursorType.Xterm}, + {StandardCursorType.No, Gtk.Stock.Cancel}, + {StandardCursorType.SizeAll, CursorType.Sizing}, //{ StandardCursorType.SizeNorthEastSouthWest, 32643 }, - { StandardCursorType.SizeNorthSouth, CursorType.SbVDoubleArrow}, + {StandardCursorType.SizeNorthSouth, CursorType.SbVDoubleArrow}, //{ StandardCursorType.SizeNorthWestSouthEast, 32642 }, - { StandardCursorType.SizeWestEast, CursorType.SbHDoubleArrow }, - { StandardCursorType.UpArrow, CursorType.BasedArrowUp }, - { StandardCursorType.Wait, CursorType.Watch }, - { StandardCursorType.Help, Gtk.Stock.Help } + {StandardCursorType.SizeWestEast, CursorType.SbHDoubleArrow}, + {StandardCursorType.UpArrow, CursorType.BasedArrowUp}, + {StandardCursorType.Wait, CursorType.Watch}, + {StandardCursorType.Help, Gtk.Stock.Help}, + {StandardCursorType.TopSide, CursorType.TopSide}, + {StandardCursorType.BottomSize, CursorType.BottomSide}, + {StandardCursorType.LeftSide, CursorType.LeftSide}, + {StandardCursorType.RightSide, CursorType.RightSide}, + {StandardCursorType.TopLeftCorner, CursorType.TopLeftCorner}, + {StandardCursorType.TopRightCorner, CursorType.TopRightCorner}, + {StandardCursorType.BottomLeftCorner, CursorType.BottomLeftCorner}, + {StandardCursorType.BottomRightCorner, CursorType.BottomRightCorner} }; private static readonly Dictionary Cache = diff --git a/src/Perspex.Input/Cursors.cs b/src/Perspex.Input/Cursors.cs index 889cc68774..34f97fe0a6 100644 --- a/src/Perspex.Input/Cursors.cs +++ b/src/Perspex.Input/Cursors.cs @@ -30,7 +30,15 @@ namespace Perspex.Input No, Hand, AppStarting, - Help + Help, + TopSide, + BottomSize, + LeftSide, + RightSide, + TopLeftCorner, + TopRightCorner, + BottomLeftCorner, + BottomRightCorner // Not available in GTK directly, see http://www.pixelbeat.org/programming/x_cursors/ // We might enable them later, preferably, by loading pixmax direclty from theme with fallback image diff --git a/src/Windows/Perspex.Win32/CursorFactory.cs b/src/Windows/Perspex.Win32/CursorFactory.cs index ad2defac35..fd117f6814 100644 --- a/src/Windows/Perspex.Win32/CursorFactory.cs +++ b/src/Windows/Perspex.Win32/CursorFactory.cs @@ -23,22 +23,30 @@ namespace Perspex.Win32 private static readonly Dictionary CursorTypeMapping = new Dictionary { - { StandardCursorType.AppStarting, 32650 }, - { StandardCursorType.Arrow, 32512 }, - { StandardCursorType.Cross, 32515 }, - { StandardCursorType.Hand, 32649 }, - { StandardCursorType.Help, 32651 }, - { StandardCursorType.Ibeam, 32513 }, - { StandardCursorType.No, 32648 }, - { StandardCursorType.SizeAll, 32646 }, - - // { StandardCursorType.SizeNorthEastSouthWest, 32643 }, - { StandardCursorType.SizeNorthSouth, 32645 }, - - // { StandardCursorType.SizeNorthWestSouthEast, 32642 }, - { StandardCursorType.SizeWestEast, 32644 }, - { StandardCursorType.UpArrow, 32516 }, - { StandardCursorType.Wait, 32514 } + {StandardCursorType.AppStarting, 32650}, + {StandardCursorType.Arrow, 32512}, + {StandardCursorType.Cross, 32515}, + {StandardCursorType.Hand, 32649}, + {StandardCursorType.Help, 32651}, + {StandardCursorType.Ibeam, 32513}, + {StandardCursorType.No, 32648}, + {StandardCursorType.SizeAll, 32646}, + {StandardCursorType.UpArrow, 32516}, + {StandardCursorType.SizeNorthSouth, 32645}, + {StandardCursorType.SizeWestEast, 32644}, + {StandardCursorType.Wait, 32514}, + //Same as SizeNorthSouth + {StandardCursorType.TopSide, 32645}, + {StandardCursorType.BottomSize, 32645}, + //Same as SizeWestEast + {StandardCursorType.LeftSide, 32644}, + {StandardCursorType.RightSide, 32644}, + //Using SizeNorthWestSouthEast + {StandardCursorType.TopLeftCorner, 32642}, + {StandardCursorType.BottomRightCorner, 32642}, + //Using SizeNorthEastSouthWest + {StandardCursorType.TopRightCorner, 32643}, + {StandardCursorType.BottomLeftCorner, 32643}, }; private static readonly Dictionary Cache = From 84af63ce1e4cf944c266fe8a880ee712eb0b3385 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Sun, 13 Dec 2015 05:19:24 +0300 Subject: [PATCH 09/12] Added Position property, moved Hide/Show to ITopLevelImpl --- .../Platform/SkiaPlatform/WindowImpl.cs | 2 ++ src/Gtk/Perspex.Gtk/PopupImpl.cs | 5 ----- src/Gtk/Perspex.Gtk/WindowImpl.cs | 14 ++++++++++++ src/Perspex.Controls/Platform/IPopupImpl.cs | 9 -------- .../Platform/ITopLevelImpl.cs | 7 ++++++ src/Perspex.Controls/Platform/IWindowImpl.cs | 5 ----- .../Platform/PlatformManager.cs | 11 +++++----- src/Perspex.Controls/Primitives/Popup.cs | 2 +- src/Perspex.Controls/Primitives/PopupRoot.cs | 9 -------- src/Perspex.Controls/ToolTip.cs | 2 +- src/Perspex.Controls/TopLevel.cs | 6 +++++ src/Windows/Perspex.Win32/PopupImpl.cs | 12 ---------- src/Windows/Perspex.Win32/WindowImpl.cs | 22 +++++++++++++++++++ src/iOS/Perspex.iOS/PerspexView.cs | 2 ++ 14 files changed, 61 insertions(+), 47 deletions(-) diff --git a/src/Android/Perspex.Android/Platform/SkiaPlatform/WindowImpl.cs b/src/Android/Perspex.Android/Platform/SkiaPlatform/WindowImpl.cs index 14bd084a37..ed853a4353 100644 --- a/src/Android/Perspex.Android/Platform/SkiaPlatform/WindowImpl.cs +++ b/src/Android/Perspex.Android/Platform/SkiaPlatform/WindowImpl.cs @@ -137,6 +137,8 @@ namespace Perspex.Android.Platform.SkiaPlatform //Not supported } + public Point Position { get; set; } + public IDisposable ShowDialog() { throw new NotImplementedException(); diff --git a/src/Gtk/Perspex.Gtk/PopupImpl.cs b/src/Gtk/Perspex.Gtk/PopupImpl.cs index 8e432e2448..63e34460b4 100644 --- a/src/Gtk/Perspex.Gtk/PopupImpl.cs +++ b/src/Gtk/Perspex.Gtk/PopupImpl.cs @@ -12,10 +12,5 @@ namespace Perspex.Gtk : base(WindowType.Popup) { } - - public void SetPosition(Point p) - { - Move((int)p.X, (int)p.Y); - } } } diff --git a/src/Gtk/Perspex.Gtk/WindowImpl.cs b/src/Gtk/Perspex.Gtk/WindowImpl.cs index 01054ae50b..0435a052ba 100644 --- a/src/Gtk/Perspex.Gtk/WindowImpl.cs +++ b/src/Gtk/Perspex.Gtk/WindowImpl.cs @@ -179,6 +179,20 @@ namespace Perspex.Gtk BeginResizeDrag((Gdk.WindowEdge) (int) edge, 1, x, y, 0); } + public Point Position + { + get + { + int x, y; + GetPosition(out x, out y); + return new Point(x, y); + } + set + { + Move((int)value.X, (int)value.Y); + } + } + public IDisposable ShowDialog() { Modal = true; diff --git a/src/Perspex.Controls/Platform/IPopupImpl.cs b/src/Perspex.Controls/Platform/IPopupImpl.cs index 495b16409c..5cbdafb9f9 100644 --- a/src/Perspex.Controls/Platform/IPopupImpl.cs +++ b/src/Perspex.Controls/Platform/IPopupImpl.cs @@ -8,15 +8,6 @@ namespace Perspex.Platform /// public interface IPopupImpl : ITopLevelImpl { - /// - /// Sets the position of the popup. - /// - /// The position, in screen coordinates. - void SetPosition(Point p); - /// - /// Hides the popup. - /// - void Hide(); } } diff --git a/src/Perspex.Controls/Platform/ITopLevelImpl.cs b/src/Perspex.Controls/Platform/ITopLevelImpl.cs index 0a11566c5a..7c80b951a5 100644 --- a/src/Perspex.Controls/Platform/ITopLevelImpl.cs +++ b/src/Perspex.Controls/Platform/ITopLevelImpl.cs @@ -89,6 +89,11 @@ namespace Perspex.Platform /// Shows the toplevel. /// void Show(); + + /// + /// Hides the window. + /// + void Hide(); /// /// Starts moving a window with left button being held. Should be called from left mouse button press event handler. @@ -100,5 +105,7 @@ namespace Perspex.Platform /// Should be called from left mouse button press event handler /// void BeginResizeDrag(WindowEdge edge); + + Point Position { get; set; } } } diff --git a/src/Perspex.Controls/Platform/IWindowImpl.cs b/src/Perspex.Controls/Platform/IWindowImpl.cs index e27d94b41e..cb266a9153 100644 --- a/src/Perspex.Controls/Platform/IWindowImpl.cs +++ b/src/Perspex.Controls/Platform/IWindowImpl.cs @@ -29,11 +29,6 @@ namespace Perspex.Platform /// IDisposable ShowDialog(); - /// - /// Hides the window. - /// - void Hide(); - /// /// Enables of disables system window decorations (title bar, buttons, etc) /// diff --git a/src/Perspex.Controls/Platform/PlatformManager.cs b/src/Perspex.Controls/Platform/PlatformManager.cs index fc582ab45d..6cec6cfadf 100644 --- a/src/Perspex.Controls/Platform/PlatformManager.cs +++ b/src/Perspex.Controls/Platform/PlatformManager.cs @@ -155,11 +155,6 @@ namespace Perspex.Controls.Platform set { _tl.Deactivated = value; } } - public void SetPosition(Point p) - { - _popup.SetPosition(p*ScalingFactor); - } - public void Dispose() => _tl.Dispose(); public IPlatformHandle Handle => _tl.Handle; @@ -177,6 +172,12 @@ namespace Perspex.Controls.Platform public void BeginMoveDrag() => _tl.BeginMoveDrag(); public void BeginResizeDrag(WindowEdge edge) => _tl.BeginResizeDrag(edge); + public Point Position + { + get { return _tl.Position; } + set { _tl.Position = value; } + } + public IDisposable ShowDialog() => _window.ShowDialog(); public void Hide() => _popup.Hide(); diff --git a/src/Perspex.Controls/Primitives/Popup.cs b/src/Perspex.Controls/Primitives/Popup.cs index e3f4183a1a..c074d26874 100644 --- a/src/Perspex.Controls/Primitives/Popup.cs +++ b/src/Perspex.Controls/Primitives/Popup.cs @@ -169,7 +169,7 @@ namespace Perspex.Controls.Primitives ((ISetLogicalParent)_popupRoot).SetParent(this); } - _popupRoot.SetPosition(GetPosition()); + _popupRoot.Position = GetPosition(); _popupRoot.AddHandler(PointerPressedEvent, MaybeClose, RoutingStrategies.Bubble, true); if (_topLevel != null) diff --git a/src/Perspex.Controls/Primitives/PopupRoot.cs b/src/Perspex.Controls/Primitives/PopupRoot.cs index b69af20c3f..9abf981642 100644 --- a/src/Perspex.Controls/Primitives/PopupRoot.cs +++ b/src/Perspex.Controls/Primitives/PopupRoot.cs @@ -65,15 +65,6 @@ namespace Perspex.Controls.Primitives /// IVisual IHostedVisualTreeRoot.Host => Parent; - /// - /// Sets the position of the popup in screen coordinates. - /// - /// The position. - public void SetPosition(Point p) - { - PlatformImpl.SetPosition(p); - } - /// /// Hides the popup. /// diff --git a/src/Perspex.Controls/ToolTip.cs b/src/Perspex.Controls/ToolTip.cs index 8be91f237b..559db90ff3 100644 --- a/src/Perspex.Controls/ToolTip.cs +++ b/src/Perspex.Controls/ToolTip.cs @@ -118,7 +118,7 @@ namespace Perspex.Controls var position = control.PointToScreen(cp ?? new Point(0, 0)) + new Vector(0, 22); ((ToolTip)s_popup.Content).Content = GetTip(control); - s_popup.SetPosition(position); + s_popup.Position = position; s_popup.Show(); s_current = control; diff --git a/src/Perspex.Controls/TopLevel.cs b/src/Perspex.Controls/TopLevel.cs index 12311df1c9..f167c62770 100644 --- a/src/Perspex.Controls/TopLevel.cs +++ b/src/Perspex.Controls/TopLevel.cs @@ -375,5 +375,11 @@ namespace Perspex.Controls /// Should be called from left mouse button press event handler /// public void BeginResizeDrag(WindowEdge edge) => PlatformImpl.BeginResizeDrag(edge); + + public Point Position + { + get { return PlatformImpl.Position; } + set { PlatformImpl.Position = value; } + } } } diff --git a/src/Windows/Perspex.Win32/PopupImpl.cs b/src/Windows/Perspex.Win32/PopupImpl.cs index 8161df4c65..2d73da88b0 100644 --- a/src/Windows/Perspex.Win32/PopupImpl.cs +++ b/src/Windows/Perspex.Win32/PopupImpl.cs @@ -9,18 +9,6 @@ namespace Perspex.Win32 { public class PopupImpl : WindowImpl, IPopupImpl { - public void SetPosition(Point p) - { - UnmanagedMethods.SetWindowPos( - Handle.Handle, - IntPtr.Zero, - (int)p.X, - (int)p.Y, - 0, - 0, - UnmanagedMethods.SetWindowPosFlags.SWP_NOSIZE | UnmanagedMethods.SetWindowPosFlags.SWP_NOACTIVATE); - } - public override void Show() { UnmanagedMethods.ShowWindow(Handle.Handle, UnmanagedMethods.ShowWindowCommand.ShowNoActivate); diff --git a/src/Windows/Perspex.Win32/WindowImpl.cs b/src/Windows/Perspex.Win32/WindowImpl.cs index ca1a2ae9c6..49383c10e3 100644 --- a/src/Windows/Perspex.Win32/WindowImpl.cs +++ b/src/Windows/Perspex.Win32/WindowImpl.cs @@ -247,6 +247,28 @@ namespace Perspex.Win32 new IntPtr((int) EdgeDic[edge]), IntPtr.Zero); } + public Point Position + { + get + { + UnmanagedMethods.RECT rc; + UnmanagedMethods.GetWindowRect(_hwnd, out rc); + return new Point(rc.left, rc.top); + } + set + { + UnmanagedMethods.SetWindowPos( + Handle.Handle, + IntPtr.Zero, + (int) value.X, + (int) value.Y, + 0, + 0, + UnmanagedMethods.SetWindowPosFlags.SWP_NOSIZE | UnmanagedMethods.SetWindowPosFlags.SWP_NOACTIVATE); + + } + } + public virtual IDisposable ShowDialog() { var disabled = s_instances.Where(x => x != this && x.IsEnabled).ToList(); diff --git a/src/iOS/Perspex.iOS/PerspexView.cs b/src/iOS/Perspex.iOS/PerspexView.cs index 92b2fac730..fca1e28a1c 100644 --- a/src/iOS/Perspex.iOS/PerspexView.cs +++ b/src/iOS/Perspex.iOS/PerspexView.cs @@ -118,6 +118,8 @@ namespace Perspex.iOS //Not supported } + public Point Position { get; set; } + public Size MaxClientSize => Bounds.Size.ToPerspex(); public void SetTitle(string title) { From 6d8263b778a44309cb52b0426894bb620b5c4630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Manuel=20Nieto=20S=C3=A1nchez?= Date: Sun, 13 Dec 2015 22:12:23 +0100 Subject: [PATCH 10/12] Adaptation to newest changes in OmniXAML --- .../Perspex.Markup.Xaml/Context/PerspexObjectAssembler.cs | 2 ++ src/Markup/Perspex.Markup.Xaml/OmniXAML | 2 +- src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj | 4 ++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Markup/Perspex.Markup.Xaml/Context/PerspexObjectAssembler.cs b/src/Markup/Perspex.Markup.Xaml/Context/PerspexObjectAssembler.cs index 2a9a88219f..788bfd3ced 100644 --- a/src/Markup/Perspex.Markup.Xaml/Context/PerspexObjectAssembler.cs +++ b/src/Markup/Perspex.Markup.Xaml/Context/PerspexObjectAssembler.cs @@ -29,6 +29,8 @@ namespace Perspex.Markup.Xaml.Context public object Result => _objectAssembler.Result; + public InstanceLifeCycleHandler InstanceLifeCycleHandler { get; set; } = new InstanceLifeCycleHandler(); + public EventHandler XamlSetValueHandler { get; set; } public IWiringContext WiringContext => _objectAssembler.WiringContext; diff --git a/src/Markup/Perspex.Markup.Xaml/OmniXAML b/src/Markup/Perspex.Markup.Xaml/OmniXAML index f2673838c0..0904dcb071 160000 --- a/src/Markup/Perspex.Markup.Xaml/OmniXAML +++ b/src/Markup/Perspex.Markup.Xaml/OmniXAML @@ -1 +1 @@ -Subproject commit f2673838c0422ff0f6fdb3e4b34a5302971f59b5 +Subproject commit 0904dcb07175ca0cdf2ae1fda1434c0f1425a53e diff --git a/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj b/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj index 484363cd85..69b6143bbc 100644 --- a/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj +++ b/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj @@ -109,6 +109,7 @@ + @@ -119,6 +120,7 @@ + @@ -130,6 +132,7 @@ + @@ -141,6 +144,7 @@ + From d2bbe8e08e8fe71e7078cad6c0dabc9a547df38b Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 14 Dec 2015 22:22:20 +0000 Subject: [PATCH 11/12] Test event handling works as expected. --- .../InteractiveTests.cs | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tests/Perspex.Interactivity.UnitTests/InteractiveTests.cs b/tests/Perspex.Interactivity.UnitTests/InteractiveTests.cs index 3a3d47947a..c26ecf0ecb 100644 --- a/tests/Perspex.Interactivity.UnitTests/InteractiveTests.cs +++ b/tests/Perspex.Interactivity.UnitTests/InteractiveTests.cs @@ -117,6 +117,52 @@ namespace Perspex.Interactivity.UnitTests invoked); } + [Fact] + public void Handled_Bubbled_Event_Should_Not_Propogate_Further() + { + var ev = new RoutedEvent("test", RoutingStrategies.Bubble, typeof(RoutedEventArgs), typeof(TestInteractive)); + var invoked = new List(); + + EventHandler handler = (s, e) => + { + var t = (TestInteractive)s; + invoked.Add(t.Name); + e.Handled = t.Name == "2b"; + }; + + var target = CreateTree(ev, handler, RoutingStrategies.Bubble); + + var args = new RoutedEventArgs(ev, target); + target.RaiseEvent(args); + + Assert.Equal(new[] { "2b" }, invoked); + } + + [Fact] + public void Handled_Tunnelled_Event_Should_Not_Propogate_Further() + { + var ev = new RoutedEvent( + "test", + RoutingStrategies.Bubble | RoutingStrategies.Tunnel, + typeof(RoutedEventArgs), + typeof(TestInteractive)); + var invoked = new List(); + + EventHandler handler = (s, e) => + { + var t = (TestInteractive)s; + invoked.Add(t.Name); + e.Handled = t.Name == "2b"; + }; + + var target = CreateTree(ev, handler, RoutingStrategies.Bubble | RoutingStrategies.Tunnel); + + var args = new RoutedEventArgs(ev, target); + target.RaiseEvent(args); + + Assert.Equal(new[] { "1", "2b" }, invoked); + } + [Fact] public void Direct_Subscription_Should_Not_Catch_Tunneling_Or_Bubbling() { From 23cc9a2ff44b0ef92d2b68c8de7b9dea3dcbf3d2 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 16 Dec 2015 19:01:55 +0000 Subject: [PATCH 12/12] Allow binding to element without path. Closes #365. --- .../Perspex.Markup/Data/ExpressionObserver.cs | 4 + .../Data/BindingTests_ElementName.cs | 77 ++++++++++++++++++- 2 files changed, 79 insertions(+), 2 deletions(-) diff --git a/src/Markup/Perspex.Markup/Data/ExpressionObserver.cs b/src/Markup/Perspex.Markup/Data/ExpressionObserver.cs index e8df013d50..3f529c11cb 100644 --- a/src/Markup/Perspex.Markup/Data/ExpressionObserver.cs +++ b/src/Markup/Perspex.Markup/Data/ExpressionObserver.cs @@ -204,6 +204,10 @@ namespace Perspex.Markup.Data subscription.Dispose(); }); } + else if (_rootObservable != null) + { + return _rootObservable.Subscribe(observer); + } else { if (_empty == null) diff --git a/tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests_ElementName.cs b/tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests_ElementName.cs index bde7297d47..c47d53d0a3 100644 --- a/tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests_ElementName.cs +++ b/tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests_ElementName.cs @@ -10,7 +10,7 @@ namespace Perspex.Markup.Xaml.UnitTests.Data public class BindingTests_ElementName { [Fact] - public void Should_Bind_To_Element() + public void Should_Bind_To_Element_Path() { TextBlock target; var root = new TestRoot @@ -44,7 +44,42 @@ namespace Perspex.Markup.Xaml.UnitTests.Data } [Fact] - public void Should_Bind_To_Later_Added_Element() + public void Should_Bind_To_Element() + { + TextBlock source; + ContentControl target; + + var root = new TestRoot + { + Child = new StackPanel + { + Children = new Controls.Controls + { + (source = new TextBlock + { + Name = "source", + Text = "foo", + }), + (target = new ContentControl + { + Name = "target", + }) + } + } + }; + + var binding = new Binding + { + ElementName = "source", + }; + + binding.Bind(target, ContentControl.ContentProperty); + + Assert.Same(source, target.Content); + } + + [Fact] + public void Should_Bind_To_Later_Added_Element_Path() { TextBlock target; StackPanel stackPanel; @@ -79,5 +114,43 @@ namespace Perspex.Markup.Xaml.UnitTests.Data Assert.Equal("foo", target.Text); } + + [Fact] + public void Should_Bind_To_Later_Added_Element() + { + ContentControl target; + StackPanel stackPanel; + + var root = new TestRoot + { + Child = stackPanel = new StackPanel + { + Children = new Controls.Controls + { + (target = new ContentControl + { + Name = "target", + }), + } + } + }; + + var binding = new Binding + { + ElementName = "source", + }; + + binding.Bind(target, ContentControl.ContentProperty); + + var source = new TextBlock + { + Name = "source", + Text = "foo", + }; + + stackPanel.Children.Add(source); + + Assert.Same(source, target.Content); + } } }