Browse Source

Merge branch 'master' into leaks

pull/366/head
Steven Kirk 11 years ago
parent
commit
cd721f1ae8
  1. 16
      src/Android/Perspex.Android/Platform/SkiaPlatform/WindowImpl.cs
  2. 32
      src/Gtk/Perspex.Gtk/CursorFactory.cs
  3. 5
      src/Gtk/Perspex.Gtk/PopupImpl.cs
  4. 33
      src/Gtk/Perspex.Gtk/WindowImpl.cs
  5. 2
      src/Markup/Perspex.Markup.Xaml/Context/PerspexObjectAssembler.cs
  6. 1
      src/Markup/Perspex.Markup.Xaml/Context/PerspexWiringContext.cs
  7. 36
      src/Markup/Perspex.Markup.Xaml/Converters/CursorTypeConverter.cs
  8. 2
      src/Markup/Perspex.Markup.Xaml/OmniXAML
  9. 5
      src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj
  10. 4
      src/Markup/Perspex.Markup/Data/ExpressionObserver.cs
  11. 1
      src/Perspex.Controls/Perspex.Controls.csproj
  12. 9
      src/Perspex.Controls/Platform/IPopupImpl.cs
  13. 19
      src/Perspex.Controls/Platform/ITopLevelImpl.cs
  14. 4
      src/Perspex.Controls/Platform/IWindowImpl.cs
  15. 14
      src/Perspex.Controls/Platform/PlatformManager.cs
  16. 2
      src/Perspex.Controls/Primitives/Popup.cs
  17. 9
      src/Perspex.Controls/Primitives/PopupRoot.cs
  18. 2
      src/Perspex.Controls/ToolTip.cs
  19. 17
      src/Perspex.Controls/TopLevel.cs
  20. 18
      src/Perspex.Controls/Window.cs
  21. 17
      src/Perspex.Controls/WindowEdge.cs
  22. 10
      src/Perspex.Input/Cursors.cs
  23. 39
      src/Perspex.SceneGraph/Media/PathMarkupParser.cs
  24. 40
      src/Windows/Perspex.Win32/CursorFactory.cs
  25. 31
      src/Windows/Perspex.Win32/Interop/UnmanagedMethods.cs
  26. 12
      src/Windows/Perspex.Win32/PopupImpl.cs
  27. 89
      src/Windows/Perspex.Win32/WindowImpl.cs
  28. 25
      src/iOS/Perspex.iOS/PerspexView.cs
  29. 46
      tests/Perspex.Interactivity.UnitTests/InteractiveTests.cs
  30. 77
      tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests_ElementName.cs

16
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
{
@ -94,6 +95,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();
@ -123,6 +127,18 @@ namespace Perspex.Android.Platform.SkiaPlatform
this.Visibility = ViewStates.Visible;
}
public void BeginMoveDrag()
{
//Not supported
}
public void BeginResizeDrag(WindowEdge edge)
{
//Not supported
}
public Point Position { get; set; }
public IDisposable ShowDialog()
{
throw new NotImplementedException();

32
src/Gtk/Perspex.Gtk/CursorFactory.cs

@ -21,20 +21,28 @@ namespace Perspex.Gtk
private static readonly Dictionary<StandardCursorType, object> CursorTypeMapping = new Dictionary
<StandardCursorType, object>
{
{ 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<StandardCursorType, IPlatformHandle> Cache =

5
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);
}
}
}

33
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
{
@ -162,6 +163,36 @@ 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(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 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;
@ -170,6 +201,8 @@ namespace Perspex.Gtk
return Disposable.Empty;
}
public void SetSystemDecorations(bool enabled) => Decorated = enabled;
void ITopLevelImpl.Activate()
{
Activate();

2
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<XamlSetValueEventArgs> XamlSetValueHandler { get; set; }
public IWiringContext WiringContext => _objectAssembler.WiringContext;

1
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);

36
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();
}
}
}

2
src/Markup/Perspex.Markup.Xaml/OmniXAML

@ -1 +1 @@
Subproject commit f2673838c0422ff0f6fdb3e4b34a5302971f59b5
Subproject commit 0904dcb07175ca0cdf2ae1fda1434c0f1425a53e

5
src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj

@ -39,6 +39,7 @@
<Link>Properties\SharedAssemblyInfo.cs</Link>
</Compile>
<Compile Include="Context\NameScopeWrapper.cs" />
<Compile Include="Converters\CursorTypeConverter.cs" />
<Compile Include="Converters\PerspexListTypeConverter.cs" />
<Compile Include="Converters\RelativeRectTypeConverter.cs" />
<Compile Include="Data\IXamlBinding.cs" />
@ -108,6 +109,7 @@
<Compile Include="OmniXAML\Source\OmniXaml\IDeferredLoader.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\IMarkupExtension.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\INameScope.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\InstanceLifeCycleHandler.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\InstructionNode.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\InstructionTreeBuilder.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\IObjectAssembler.cs" />
@ -118,6 +120,7 @@
<Compile Include="OmniXAML\Source\OmniXaml\ITypeProvider.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\IValueConverter.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\IWiringContext.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\IXamlLoader.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\IXamlParser.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\IXamlParserFactory.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\IXamlXmlLoader.cs" />
@ -129,6 +132,7 @@
<Compile Include="OmniXAML\Source\OmniXaml\MemberReverserVisitor.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\NamespaceDeclaration.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\NamespacePrefix.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\ObjectAssemblerMixin.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\ObjectAssembler\Command.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\ObjectAssembler\Commands\EndMemberCommand.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\ObjectAssembler\Commands\EndObjectCommand.cs" />
@ -140,6 +144,7 @@
<Compile Include="OmniXAML\Source\OmniXaml\ObjectAssembler\Commands\ValueCommand.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\ObjectAssembler\ConstructionArgument.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\ObjectAssembler\CurrentLevelWrapper.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\ObjectAssembler\InstanceLifeCycleNotifier.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\ObjectAssembler\InstanceProperties.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\ObjectAssembler\Level.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\ObjectAssembler\NullLevel.cs" />

4
src/Markup/Perspex.Markup/Data/ExpressionObserver.cs

@ -201,6 +201,10 @@ namespace Perspex.Markup.Data
subscription.Dispose();
});
}
else if (_rootObservable != null)
{
return _rootObservable.Subscribe(observer);
}
else
{
if (_update == null)

1
src/Perspex.Controls/Perspex.Controls.csproj

@ -176,6 +176,7 @@
<Compile Include="TreeView.cs" />
<Compile Include="TreeViewItem.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="WindowEdge.cs" />
<Compile Include="WrapPanel.cs" />
</ItemGroup>
<ItemGroup>

9
src/Perspex.Controls/Platform/IPopupImpl.cs

@ -8,15 +8,6 @@ namespace Perspex.Platform
/// </summary>
public interface IPopupImpl : ITopLevelImpl
{
/// <summary>
/// Sets the position of the popup.
/// </summary>
/// <param name="p">The position, in screen coordinates.</param>
void SetPosition(Point p);
/// <summary>
/// Hides the popup.
/// </summary>
void Hide();
}
}

19
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;
@ -88,5 +89,23 @@ namespace Perspex.Platform
/// Shows the toplevel.
/// </summary>
void Show();
/// <summary>
/// Hides the window.
/// </summary>
void Hide();
/// <summary>
/// Starts moving a window with left button being held. Should be called from left mouse button press event handler.
/// </summary>
void BeginMoveDrag();
/// <summary>
/// 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
/// </summary>
void BeginResizeDrag(WindowEdge edge);
Point Position { get; set; }
}
}

4
src/Perspex.Controls/Platform/IWindowImpl.cs

@ -30,8 +30,8 @@ namespace Perspex.Platform
IDisposable ShowDialog();
/// <summary>
/// Hides the window.
/// Enables of disables system window decorations (title bar, buttons, etc)
/// </summary>
void Hide();
void SetSystemDecorations(bool enabled);
}
}

14
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;
@ -174,10 +169,19 @@ namespace Perspex.Controls.Platform
public void SetTitle(string title) => _window.SetTitle(title);
public void Show() => _tl.Show();
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();
public void SetSystemDecorations(bool enabled) => _window.SetSystemDecorations(enabled);
}
public static IWindowImpl CreateWindow()

2
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)

9
src/Perspex.Controls/Primitives/PopupRoot.cs

@ -64,15 +64,6 @@ namespace Perspex.Controls.Primitives
/// </summary>
IVisual IHostedVisualTreeRoot.Host => Parent;
/// <summary>
/// Sets the position of the popup in screen coordinates.
/// </summary>
/// <param name="p">The position.</param>
public void SetPosition(Point p)
{
PlatformImpl.SetPosition(p);
}
/// <summary>
/// Hides the popup.
/// </summary>

2
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;

17
src/Perspex.Controls/TopLevel.cs

@ -369,5 +369,22 @@ namespace Perspex.Controls
{
_renderQueueManager?.InvalidateRender(this);
}
/// <summary>
/// Starts moving a window with left button being held. Should be called from left mouse button press event handler
/// </summary>
public void BeginMoveDrag() => PlatformImpl.BeginMoveDrag();
/// <summary>
/// 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
/// </summary>
public void BeginResizeDrag(WindowEdge edge) => PlatformImpl.BeginResizeDrag(edge);
public Point Position
{
get { return PlatformImpl.Position; }
set { PlatformImpl.Position = value; }
}
}
}

18
src/Perspex.Controls/Window.cs

@ -49,6 +49,12 @@ namespace Perspex.Controls
public static readonly PerspexProperty<SizeToContent> SizeToContentProperty =
PerspexProperty.Register<Window, SizeToContent>(nameof(SizeToContent));
/// <summary>
/// Enables of disables system window decorations (title bar, buttons, etc)
/// </summary>
public static readonly PerspexProperty<bool> HasSystemDecorationsProperty =
PerspexProperty.Register<Window, bool>(nameof(HasSystemDecorations), true);
/// <summary>
/// Defines the <see cref="Title"/> property.
/// </summary>
@ -66,6 +72,8 @@ namespace Perspex.Controls
{
BackgroundProperty.OverrideDefaultValue(typeof(Window), Brushes.White);
TitleProperty.Changed.AddClassHandler<Window>((s, e) => s.PlatformImpl.SetTitle((string)e.NewValue));
HasSystemDecorationsProperty.Changed.AddClassHandler<Window>(
(s, e) => s.PlatformImpl.SetSystemDecorations((bool) e.NewValue));
}
/// <summary>
@ -114,6 +122,16 @@ namespace Perspex.Controls
set { SetValue(TitleProperty, value); }
}
/// <summary>
/// Enables of disables system window decorations (title bar, buttons, etc)
/// </summary>
///
public bool HasSystemDecorations
{
get { return GetValue(HasSystemDecorationsProperty); }
set { SetValue(HasSystemDecorationsProperty, value); }
}
/// <inheritdoc/>
Type IStyleable.StyleKey => typeof(Window);

17
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,
}
}

10
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

39
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
}
}
}
}
}

40
src/Windows/Perspex.Win32/CursorFactory.cs

@ -23,22 +23,30 @@ namespace Perspex.Win32
private static readonly Dictionary<StandardCursorType, int> CursorTypeMapping = new Dictionary
<StandardCursorType, int>
{
{ 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<StandardCursorType, IPlatformHandle> Cache =

31
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
{
@ -571,6 +599,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);

12
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);

89
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
@ -180,6 +223,52 @@ namespace Perspex.Win32
UnmanagedMethods.ShowWindow(_hwnd, UnmanagedMethods.ShowWindowCommand.Normal);
}
public void BeginMoveDrag()
{
UnmanagedMethods.DefWindowProc(_hwnd, (int) UnmanagedMethods.WindowsMessage.WM_NCLBUTTONDOWN,
new IntPtr((int)UnmanagedMethods.HitTestValues.HTCAPTION), IntPtr.Zero);
}
static readonly Dictionary<WindowEdge, UnmanagedMethods.HitTestValues> EdgeDic = new Dictionary<WindowEdge, UnmanagedMethods.HitTestValues>
{
{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 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();

25
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
{
@ -107,6 +108,18 @@ namespace Perspex.iOS
_keyboardHelper.ActivateAutoShowKeybord();
}
public void BeginMoveDrag()
{
//Not supported
}
public void BeginResizeDrag(WindowEdge edge)
{
//Not supported
}
public Point Position { get; set; }
public Size MaxClientSize => Bounds.Size.ToPerspex();
public void SetTitle(string title)
{
@ -124,6 +137,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;
@ -168,14 +186,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<IPlatformSettings>().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;
}

46
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<string>();
EventHandler<RoutedEventArgs> 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<string>();
EventHandler<RoutedEventArgs> 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()
{

77
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);
}
}
}

Loading…
Cancel
Save