From 991e42143783beda359295f39695a16c52fe787d Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Thu, 26 Nov 2015 23:31:16 +0300 Subject: [PATCH 1/6] Now using built-in designer API instead of dynamic calls --- .../Perspex.Android/AndroidPlatform.cs | 22 +++++- src/Gtk/Perspex.Gtk/GtkPlatform.cs | 19 ++++- .../Perspex.Markup.Xaml.csproj | 4 - src/Perspex.Application/Designer/Designer.cs | 58 ++++++++++++++ .../Designer/DesignerApi.cs | 51 ++++++++++++ .../Perspex.Application.csproj | 19 ++++- src/Perspex.Base/Perspex.Base.csproj | 1 + .../Platform/IAssetLoader.cs | 0 src/Perspex.Controls/Perspex.Controls.csproj | 1 + .../Platform/IWindowingPlatform.cs | 15 ++++ .../Platform/PlatformManager.cs | 14 +++- .../AppHost/PerspexAppHost.cs | 77 ++++++------------- .../Perspex.Designer/Perspex.Designer.csproj | 3 + src/Windows/Perspex.Win32/Win32Platform.cs | 35 +++++---- src/iOS/Perspex.iOS/PerspexAppDelegate.cs | 27 ++++++- 15 files changed, 261 insertions(+), 85 deletions(-) create mode 100644 src/Perspex.Application/Designer/Designer.cs create mode 100644 src/Perspex.Application/Designer/DesignerApi.cs rename src/{Perspex.Application => Perspex.Base}/Platform/IAssetLoader.cs (100%) create mode 100644 src/Perspex.Controls/Platform/IWindowingPlatform.cs diff --git a/src/Android/Perspex.Android/AndroidPlatform.cs b/src/Android/Perspex.Android/AndroidPlatform.cs index b3f4bdaa32..9276cba150 100644 --- a/src/Android/Perspex.Android/AndroidPlatform.cs +++ b/src/Android/Perspex.Android/AndroidPlatform.cs @@ -10,10 +10,11 @@ using Perspex.Shared.PlatformSupport; using Perspex.Skia; using System; using System.Collections.Generic; +using Perspex.Android.Platform.SkiaPlatform; namespace Perspex.Android { - public class AndroidPlatform : IPlatformSettings + public class AndroidPlatform : IPlatformSettings, IWindowingPlatform { public static readonly AndroidPlatform Instance = new AndroidPlatform(); public Size DoubleClickSize => new Size(4, 4); @@ -33,11 +34,11 @@ namespace Perspex.Android .Bind().ToConstant(this) .Bind().ToConstant(new AndroidThreadingInterface()) .Bind().ToTransient() - .Bind().ToTransient(); + .Bind().ToTransient() + .Bind().ToConstant(this); SkiaPlatform.Initialize(); Application.RegisterPlatformCallback(() => { }); - PerspexLocator.CurrentMutable.Bind().ToSingleton(); _scalingFactor = global::Android.App.Application.Context.Resources.DisplayMetrics.ScaledDensity; @@ -50,5 +51,20 @@ namespace Perspex.Android { SharedPlatform.Register(applicationType.Assembly); } + + public IWindowImpl CreateWindow() + { + return new WindowImpl(); + } + + public IWindowImpl CreateDesignerFriendlyWindow() + { + throw new NotImplementedException(); + } + + public IPopupImpl CreatePopup() + { + throw new NotImplementedException(); + } } } \ No newline at end of file diff --git a/src/Gtk/Perspex.Gtk/GtkPlatform.cs b/src/Gtk/Perspex.Gtk/GtkPlatform.cs index 16ba905589..014048854d 100644 --- a/src/Gtk/Perspex.Gtk/GtkPlatform.cs +++ b/src/Gtk/Perspex.Gtk/GtkPlatform.cs @@ -14,7 +14,7 @@ namespace Perspex.Gtk { using Gtk = global::Gtk; - public class GtkPlatform : IPlatformThreadingInterface, IPlatformSettings + public class GtkPlatform : IPlatformThreadingInterface, IPlatformSettings, IWindowingPlatform { private static readonly GtkPlatform s_instance = new GtkPlatform(); private static Thread _uiThread; @@ -33,8 +33,7 @@ namespace Perspex.Gtk public static void Initialize() { PerspexLocator.CurrentMutable - .Bind().ToTransient() - .Bind().ToTransient() + .Bind().ToConstant(s_instance) .Bind().ToSingleton() .Bind().ToConstant(CursorFactory.Instance) .Bind().ToConstant(GtkKeyboardDevice.Instance) @@ -86,5 +85,19 @@ namespace Perspex.Gtk public bool CurrentThreadIsLoopThread => Thread.CurrentThread == _uiThread; public event Action Signaled; + public IWindowImpl CreateWindow() + { + return new WindowImpl(); + } + + public IWindowImpl CreateDesignerFriendlyWindow() + { + throw new NotSupportedException(); + } + + public IPopupImpl CreatePopup() + { + return new PopupImpl(); + } } } \ 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 35fde7d0e4..9b8cb35162 100644 --- a/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj +++ b/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj @@ -272,10 +272,6 @@ {D211E587-D8BC-45B9-95A4-F297C8FA5200} Perspex.Animation - - {799A7BB5-3C2C-48B6-85A7-406A12C420DA} - Perspex.Application - {B09B78D8-9B26-48B0-9149-D64A2F120F3F} Perspex.Base diff --git a/src/Perspex.Application/Designer/Designer.cs b/src/Perspex.Application/Designer/Designer.cs new file mode 100644 index 0000000000..665eb3447f --- /dev/null +++ b/src/Perspex.Application/Designer/Designer.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using OmniXaml; +using Perspex.Controls; +using Perspex.Controls.Platform; +using Perspex.Markup.Xaml; +using Perspex.Themes.Default; + +namespace Perspex.Designer +{ + class Designer + { + class DesignerApp : Application + { + public DesignerApp() + { + RegisterServices(); + //For now we only support windows + InitializeSubsystems(2); + Styles = new DefaultTheme(); + } + } + + public static DesignerApi Api { get; set; } + + public static void Init(Dictionary shared) + { + Api = new DesignerApi(shared) {UpdateXaml = UpdateXaml}; + new DesignerApp(); + } + + static Window s_currentWindow; + + private static void UpdateXaml(string xaml) + { + + Window window; + using (PlatformManager.DesignerMode()) + { + var obj = ((XamlXmlLoader)new PerspexXamlLoader()).Load(new MemoryStream(Encoding.UTF8.GetBytes(xaml))); + window = obj as Window; + if (window == null) + { + window = new Window() {Content = obj}; + } + } + s_currentWindow?.Close(); + s_currentWindow = window; + window.Show(); + Api.OnWindowCreated?.Invoke(window.PlatformImpl.Handle.Handle); + Api.OnResize?.Invoke(); + } + } +} diff --git a/src/Perspex.Application/Designer/DesignerApi.cs b/src/Perspex.Application/Designer/DesignerApi.cs new file mode 100644 index 0000000000..944bd86705 --- /dev/null +++ b/src/Perspex.Application/Designer/DesignerApi.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace Perspex.Designer +{ + class DesignerApi + { + private readonly Dictionary _inner; + + public DesignerApi(Dictionary inner) + { + _inner = inner; + } + + object Get([CallerMemberName] string name = null) + { + object rv; + _inner.TryGetValue(name, out rv); + return rv; + } + + void Set(object value, [CallerMemberName] string name = null) + { + _inner[name] = value; + } + + public Action UpdateXaml + { + get { return (Action) Get(); } + set {Set(value); } + } + + public Action OnResize + { + get { return (Action) Get(); } + set { Set(value);} + } + + public Action OnWindowCreated + { + set { Set(value); } + get { return (Action) Get(); } + } + + + } +} diff --git a/src/Perspex.Application/Perspex.Application.csproj b/src/Perspex.Application/Perspex.Application.csproj index c5fe995636..08ecf9912e 100644 --- a/src/Perspex.Application/Perspex.Application.csproj +++ b/src/Perspex.Application/Perspex.Application.csproj @@ -39,6 +39,18 @@ + + {3e53a01a-b331-47f3-b828-4a5717e77a24} + Perspex.Markup.Xaml + + + {6417e941-21bc-467b-a771-0de389353ce6} + Perspex.Markup + + + {d211e587-d8bc-45b9-95a4-f297c8fa5200} + Perspex.Animation + {B09B78D8-9B26-48B0-9149-D64A2F120F3F} Perspex.Base @@ -67,13 +79,18 @@ {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F} Perspex.Styling + + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F} + Perspex.Themes.Default + Properties\SharedAssemblyInfo.cs - + + diff --git a/src/Perspex.Base/Perspex.Base.csproj b/src/Perspex.Base/Perspex.Base.csproj index 890fa666bf..deeb85a600 100644 --- a/src/Perspex.Base/Perspex.Base.csproj +++ b/src/Perspex.Base/Perspex.Base.csproj @@ -53,6 +53,7 @@ + diff --git a/src/Perspex.Application/Platform/IAssetLoader.cs b/src/Perspex.Base/Platform/IAssetLoader.cs similarity index 100% rename from src/Perspex.Application/Platform/IAssetLoader.cs rename to src/Perspex.Base/Platform/IAssetLoader.cs diff --git a/src/Perspex.Controls/Perspex.Controls.csproj b/src/Perspex.Controls/Perspex.Controls.csproj index a99b3fbbfd..80b1aba585 100644 --- a/src/Perspex.Controls/Perspex.Controls.csproj +++ b/src/Perspex.Controls/Perspex.Controls.csproj @@ -44,6 +44,7 @@ + diff --git a/src/Perspex.Controls/Platform/IWindowingPlatform.cs b/src/Perspex.Controls/Platform/IWindowingPlatform.cs new file mode 100644 index 0000000000..99176b720e --- /dev/null +++ b/src/Perspex.Controls/Platform/IWindowingPlatform.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Perspex.Platform +{ + public interface IWindowingPlatform + { + IWindowImpl CreateWindow(); + IWindowImpl CreateDesignerFriendlyWindow(); + IPopupImpl CreatePopup(); + } +} diff --git a/src/Perspex.Controls/Platform/PlatformManager.cs b/src/Perspex.Controls/Platform/PlatformManager.cs index ba239d1a46..4983fc0483 100644 --- a/src/Perspex.Controls/Platform/PlatformManager.cs +++ b/src/Perspex.Controls/Platform/PlatformManager.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reactive.Disposables; using System.Text; using System.Threading.Tasks; using Perspex.Input; @@ -17,6 +18,8 @@ namespace Perspex.Controls.Platform static IPlatformSettings GetSettings() => PerspexLocator.Current.GetService(); + static bool s_designerMode; + public static IRenderTarget CreateRenderTarget(ITopLevelImpl window) { return @@ -24,6 +27,11 @@ namespace Perspex.Controls.Platform PerspexLocator.Current.GetService().CreateRenderer(window.Handle), window); } + public static IDisposable DesignerMode() + { + s_designerMode = true; + return Disposable.Create(() => s_designerMode = false); + } class RenderTargetDecorator : IRenderTarget { @@ -165,12 +173,14 @@ namespace Perspex.Controls.Platform public static IWindowImpl CreateWindow() { - return new WindowDecorator(PerspexLocator.Current.GetService()); + var platform = PerspexLocator.Current.GetService(); + return + new WindowDecorator(s_designerMode ? platform.CreateDesignerFriendlyWindow() : platform.CreateWindow()); } public static IPopupImpl CreatePopup() { - return new WindowDecorator(PerspexLocator.Current.GetService()); + return new WindowDecorator(PerspexLocator.Current.GetService().CreatePopup()); } } } diff --git a/src/Windows/Perspex.Designer/AppHost/PerspexAppHost.cs b/src/Windows/Perspex.Designer/AppHost/PerspexAppHost.cs index 8cc1dc5096..0def6e0f3e 100644 --- a/src/Windows/Perspex.Designer/AppHost/PerspexAppHost.cs +++ b/src/Windows/Perspex.Designer/AppHost/PerspexAppHost.cs @@ -18,12 +18,11 @@ namespace Perspex.Designer.AppHost class PerspexAppHost { private string _appDir; - private CommChannel _comm; + private readonly CommChannel _comm; private string _lastXaml; private string _currentXaml; - private Func _xamlReader; private bool _initSuccess; - private HostedAppModel _appModel = new HostedAppModel(); + private readonly HostedAppModel _appModel = new HostedAppModel(); private Control _window; public PerspexAppHost(CommChannel channel) @@ -92,8 +91,6 @@ namespace Perspex.Designer.AppHost PerspexDesignerMetadata BuildMetadata(List asms, Type xmlNsAttr) { - - var rv = new PerspexDesignerMetadata() { @@ -200,34 +197,10 @@ namespace Perspex.Designer.AppHost log("Looking up Perspex types"); BuildMetadataAndSendMessageAsync(asms); - var syncContext = LookupType("Perspex.Threading.PerspexSynchronizationContext"); - syncContext.GetProperty("AutoInstall", BindingFlags.Public | BindingFlags.Static).SetValue(null, false); - - var app = Activator.CreateInstance(LookupType("Perspex.Application")); - app.GetType() - .GetMethod("RegisterServices", BindingFlags.NonPublic | BindingFlags.Instance) - .Invoke(app, null); - - LookupStaticMethod("Perspex.Direct2D1.Direct2D1Platform", "Initialize").Invoke(null, null); - LookupStaticMethod("Perspex.Win32.Win32Platform", "InitializeEmbedded").Invoke(null, null); - - app.GetType().GetProperty("Styles").GetSetMethod(true) - .Invoke(app, new[] {Activator.CreateInstance(LookupType("Perspex.Themes.Default.DefaultTheme"))}); - - - dynamic dispatcher = - LookupType("Perspex.Threading.Dispatcher") - .GetProperty("UIThread", BindingFlags.Static | BindingFlags.Public) - .GetValue(null); - - - - var xamlFactory = Activator.CreateInstance(LookupType("Perspex.Markup.Xaml.Context.PerspexParserFactory")); - - dynamic xamlLoader = - LookupType("OmniXaml.XamlLoader", "OmniXaml.XamlXmlLoader").GetConstructors().First().Invoke(new object[] {xamlFactory}); - - _xamlReader = (stream) => xamlLoader.Load(stream); + log("Initializing built-in designer"); + var dic = new Dictionary(); + Api = new DesignerApi(dic) {OnResize = OnResize, OnWindowCreated = OnWindowCreated}; + LookupStaticMethod("Perspex.Designer.Designer", "Init").Invoke(null, new object[] {dic}); _window = new Control { @@ -242,15 +215,19 @@ namespace Perspex.Designer.AppHost }; _window.CreateControl(); - new Timer {Interval = 10, Enabled = true}.Tick += delegate - { - dispatcher.RunJobs(); - }; new Timer {Interval = 200, Enabled = true}.Tick += delegate { XamlUpdater(); }; _comm.SendMessage(new WindowCreatedMessage(_window.Handle)); _initSuccess = true; } + private void OnWindowCreated(IntPtr hWnd) + { + _appModel.NativeWindowHandle = hWnd; + } + + + public DesignerApi Api { get; set; } + bool ValidateXml(string xml) { @@ -269,6 +246,11 @@ namespace Perspex.Designer.AppHost return true; } + private void OnResize() + { + + } + void XamlUpdater() { if (!_initSuccess) @@ -282,27 +264,10 @@ namespace Perspex.Designer.AppHost _appModel.SetError("Invalid markup"); return; } - - try { - const string windowType = "Perspex.Controls.Window"; - - var root = _xamlReader(new MemoryStream(Encoding.UTF8.GetBytes(_currentXaml))); - dynamic window = root; - if (root.GetType().FullName != windowType) - { - window = Activator.CreateInstance(LookupType(windowType)); - window.Content = root; - } + Api.UpdateXaml(_currentXaml); - var w = ((object) (window.PlatformImpl)).Prop("Handle"); - if (!(w is IntPtr)) - w = w.Prop("Handle"); - - var hWnd = (IntPtr) w; - _appModel.NativeWindowHandle = hWnd; - window.Show(); _appModel.SetError(null); } catch (Exception e) @@ -310,6 +275,8 @@ namespace Perspex.Designer.AppHost _appModel.SetError("XAML load error", e.ToString()); } } + + private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) { diff --git a/src/Windows/Perspex.Designer/Perspex.Designer.csproj b/src/Windows/Perspex.Designer/Perspex.Designer.csproj index f5dd8bd8ac..abb50a5279 100644 --- a/src/Windows/Perspex.Designer/Perspex.Designer.csproj +++ b/src/Windows/Perspex.Designer/Perspex.Designer.csproj @@ -67,6 +67,9 @@ + + AppHost\DesignerApi.cs + App.xaml diff --git a/src/Windows/Perspex.Win32/Win32Platform.cs b/src/Windows/Perspex.Win32/Win32Platform.cs index e461e95de3..5c8c475f17 100644 --- a/src/Windows/Perspex.Win32/Win32Platform.cs +++ b/src/Windows/Perspex.Win32/Win32Platform.cs @@ -18,7 +18,7 @@ using Perspex.Win32.Interop; namespace Perspex.Win32 { - public class Win32Platform : IPlatformThreadingInterface, IPlatformSettings + public class Win32Platform : IPlatformThreadingInterface, IPlatformSettings, IWindowingPlatform { private static readonly Win32Platform s_instance = new Win32Platform(); private static Thread _uiThread; @@ -42,34 +42,22 @@ namespace Perspex.Win32 public double RenderScalingFactor { get; } = 1; public double LayoutScalingFactor { get; } = 1; - private static void InitializeInternal() + public static void Initialize() { PerspexLocator.CurrentMutable - .Bind().ToTransient() .Bind().ToSingleton() .Bind().ToConstant(CursorFactory.Instance) .Bind().ToConstant(WindowsKeyboardDevice.Instance) .Bind().ToConstant(WindowsMouseDevice.Instance) .Bind().ToConstant(s_instance) .Bind().ToConstant(s_instance) - .Bind().ToSingleton(); + .Bind().ToSingleton() + .Bind().ToConstant(s_instance); SharedPlatform.Register(); _uiThread = Thread.CurrentThread; } - public static void Initialize() - { - PerspexLocator.CurrentMutable.Bind().ToTransient(); - InitializeInternal(); - } - - public static void InitializeEmbedded() - { - PerspexLocator.CurrentMutable.Bind().ToTransient(); - InitializeInternal(); - } - public bool HasMessages() { UnmanagedMethods.MSG msg; @@ -169,5 +157,20 @@ namespace Perspex.Win32 throw new Win32Exception(); } } + + public IWindowImpl CreateWindow() + { + return new WindowImpl(); + } + + public IWindowImpl CreateDesignerFriendlyWindow() + { + return new EmbeddedWindowImpl(); + } + + public IPopupImpl CreatePopup() + { + return new PopupImpl(); + } } } diff --git a/src/iOS/Perspex.iOS/PerspexAppDelegate.cs b/src/iOS/Perspex.iOS/PerspexAppDelegate.cs index c0296d077c..e526f3a69c 100644 --- a/src/iOS/Perspex.iOS/PerspexAppDelegate.cs +++ b/src/iOS/Perspex.iOS/PerspexAppDelegate.cs @@ -42,9 +42,34 @@ namespace Perspex.iOS .Bind().ToConstant(MouseDevice) .Bind().ToSingleton() .Bind().ToConstant(PlatformThreadingInterface.Instance) - .Bind().ToConstant(controller.PerspexView); + .Bind().ToConstant(new WindowingPlatform(controller.PerspexView)); SkiaPlatform.Initialize(); }); } + + class WindowingPlatform : IWindowingPlatform + { + private readonly IWindowImpl _window; + + public WindowingPlatform(IWindowImpl window) + { + _window = window; + } + + public IWindowImpl CreateWindow() + { + return _window; + } + + public IWindowImpl CreateDesignerFriendlyWindow() + { + throw new NotImplementedException(); + } + + public IPopupImpl CreatePopup() + { + throw new NotImplementedException(); + } + } } } From a96149842080ce4215f01eda8f2613449b695db0 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 27 Nov 2015 00:01:00 +0300 Subject: [PATCH 2/6] Implemented designer scaling --- src/Perspex.Application/Designer/Designer.cs | 9 ++++++- .../Designer/DesignerApi.cs | 5 ++++ .../Platform/PlatformManager.cs | 13 ++++++++-- .../AppHost/HostedAppModel.cs | 20 ++++++++++++++++ .../AppHost/PerspexAppHost.cs | 3 ++- .../Perspex.Designer/Comm/CommChannel.cs | 2 +- .../InProcDesigner/InProcDesignerView.xaml | 24 +++++++++++++------ 7 files changed, 64 insertions(+), 12 deletions(-) diff --git a/src/Perspex.Application/Designer/Designer.cs b/src/Perspex.Application/Designer/Designer.cs index 665eb3447f..a04e1d1fef 100644 --- a/src/Perspex.Application/Designer/Designer.cs +++ b/src/Perspex.Application/Designer/Designer.cs @@ -29,10 +29,17 @@ namespace Perspex.Designer public static void Init(Dictionary shared) { - Api = new DesignerApi(shared) {UpdateXaml = UpdateXaml}; + Api = new DesignerApi(shared) {UpdateXaml = UpdateXaml, SetScalingFactor = SetScalingFactor}; new DesignerApp(); } + private static void SetScalingFactor(double factor) + { + PlatformManager.SetDesignerScalingFactor(factor); + if (s_currentWindow != null) + s_currentWindow.PlatformImpl.ClientSize = s_currentWindow.ClientSize; + } + static Window s_currentWindow; private static void UpdateXaml(string xaml) diff --git a/src/Perspex.Application/Designer/DesignerApi.cs b/src/Perspex.Application/Designer/DesignerApi.cs index 944bd86705..aebc621786 100644 --- a/src/Perspex.Application/Designer/DesignerApi.cs +++ b/src/Perspex.Application/Designer/DesignerApi.cs @@ -46,6 +46,11 @@ namespace Perspex.Designer get { return (Action) Get(); } } + public Action SetScalingFactor + { + set { Set(value);} + get { return (Action) Get(); } + } } } diff --git a/src/Perspex.Controls/Platform/PlatformManager.cs b/src/Perspex.Controls/Platform/PlatformManager.cs index 4983fc0483..383eecd5c7 100644 --- a/src/Perspex.Controls/Platform/PlatformManager.cs +++ b/src/Perspex.Controls/Platform/PlatformManager.cs @@ -19,6 +19,7 @@ namespace Perspex.Controls.Platform => PerspexLocator.Current.GetService(); static bool s_designerMode; + private static double _designerScalingFactor = 1; public static IRenderTarget CreateRenderTarget(ITopLevelImpl window) { @@ -33,6 +34,14 @@ namespace Perspex.Controls.Platform return Disposable.Create(() => s_designerMode = false); } + public static void SetDesignerScalingFactor(double factor) + { + _designerScalingFactor = factor; + } + + static double RenderScalingFactor => (GetSettings()?.RenderScalingFactor ?? 1)*_designerScalingFactor; + static double LayoutScalingFactor => (GetSettings()?.LayoutScalingFactor ?? 1) * _designerScalingFactor; + class RenderTargetDecorator : IRenderTarget { private readonly IRenderTarget _target; @@ -53,7 +62,7 @@ namespace Perspex.Controls.Platform { var cs = _window.ClientSize; var ctx = _target.CreateDrawingContext(); - var factor = GetSettings()?.RenderScalingFactor ?? 1; + var factor = RenderScalingFactor; if (factor != 1) { ctx.PushPostTransform(Matrix.CreateScale(factor, factor)); @@ -70,7 +79,7 @@ namespace Perspex.Controls.Platform private readonly IPopupImpl _popup; public ITopLevelImpl TopLevel => _tl; - double ScalingFactor => GetSettings()?.LayoutScalingFactor ?? 1; + double ScalingFactor => LayoutScalingFactor; public WindowDecorator(ITopLevelImpl tl) { diff --git a/src/Windows/Perspex.Designer/AppHost/HostedAppModel.cs b/src/Windows/Perspex.Designer/AppHost/HostedAppModel.cs index 649b5d48ee..1be709216a 100644 --- a/src/Windows/Perspex.Designer/AppHost/HostedAppModel.cs +++ b/src/Windows/Perspex.Designer/AppHost/HostedAppModel.cs @@ -11,10 +11,16 @@ namespace Perspex.Designer.AppHost { public class HostedAppModel : INotifyPropertyChanged { + private readonly PerspexAppHost _host; private IntPtr _nativeWindowHandle; private string _error; private string _errorDetails; + internal HostedAppModel(PerspexAppHost host) + { + _host = host; + } + public IntPtr NativeWindowHandle { get { return _nativeWindowHandle; } @@ -48,12 +54,26 @@ namespace Perspex.Designer.AppHost } } + public IReadOnlyList AvailableScalingFactors => new List() {1, 2, 4, 8}; + + public double CurrentScalingFactor + { + get { return _currentScalingFactor; } + set + { + _currentScalingFactor = value; + _host.Api.SetScalingFactor(value); + } + } + public void SetError(string error, string details = null) { Error = error; ErrorDetails = details; } + double _currentScalingFactor = 1; + public event PropertyChangedEventHandler PropertyChanged; [NotifyPropertyChangedInvocator] diff --git a/src/Windows/Perspex.Designer/AppHost/PerspexAppHost.cs b/src/Windows/Perspex.Designer/AppHost/PerspexAppHost.cs index 0def6e0f3e..b855019f4c 100644 --- a/src/Windows/Perspex.Designer/AppHost/PerspexAppHost.cs +++ b/src/Windows/Perspex.Designer/AppHost/PerspexAppHost.cs @@ -22,12 +22,13 @@ namespace Perspex.Designer.AppHost private string _lastXaml; private string _currentXaml; private bool _initSuccess; - private readonly HostedAppModel _appModel = new HostedAppModel(); + private HostedAppModel _appModel; private Control _window; public PerspexAppHost(CommChannel channel) { _comm = channel; + _appModel = new HostedAppModel(this); } public void Start() diff --git a/src/Windows/Perspex.Designer/Comm/CommChannel.cs b/src/Windows/Perspex.Designer/Comm/CommChannel.cs index 4e7bc641c9..a2608c88db 100644 --- a/src/Windows/Perspex.Designer/Comm/CommChannel.cs +++ b/src/Windows/Perspex.Designer/Comm/CommChannel.cs @@ -13,7 +13,7 @@ using System.Windows.Threading; namespace Perspex.Designer.Comm { - internal class CommChannel : IDisposable + class CommChannel : IDisposable { private readonly BinaryReader _input; private readonly BinaryWriter _output; diff --git a/src/Windows/Perspex.Designer/InProcDesigner/InProcDesignerView.xaml b/src/Windows/Perspex.Designer/InProcDesigner/InProcDesignerView.xaml index 38e09688cb..795749e6f6 100644 --- a/src/Windows/Perspex.Designer/InProcDesigner/InProcDesignerView.xaml +++ b/src/Windows/Perspex.Designer/InProcDesigner/InProcDesignerView.xaml @@ -4,17 +4,27 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:appHost="clr-namespace:Perspex.Designer.AppHost" + xmlns:system="clr-namespace:System;assembly=mscorlib" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300" d:DataContext="{d:DesignInstance appHost:HostedAppModel}"> - - - - + + + + + 00% + + + + + + + (View details) - - - + + + + From 3c78704f557cc87f4cd5bf28f592df30da7e2974 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 27 Nov 2015 00:15:19 +0300 Subject: [PATCH 3/6] Fix for tests --- .../Perspex.Controls.UnitTests.csproj | 1 + .../Primitives/PopupTests.cs | 2 +- .../Primitives/WindowingPlatformMock.cs | 21 +++++++++++++++++++ .../Utils/HotKeyManagerTests.cs | 4 ++-- 4 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 tests/Perspex.Controls.UnitTests/Primitives/WindowingPlatformMock.cs diff --git a/tests/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj b/tests/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj index f299a47e6d..c441eedf59 100644 --- a/tests/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj +++ b/tests/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj @@ -88,6 +88,7 @@ + diff --git a/tests/Perspex.Controls.UnitTests/Primitives/PopupTests.cs b/tests/Perspex.Controls.UnitTests/Primitives/PopupTests.cs index 18d7867b0f..172d2320f1 100644 --- a/tests/Perspex.Controls.UnitTests/Primitives/PopupTests.cs +++ b/tests/Perspex.Controls.UnitTests/Primitives/PopupTests.cs @@ -267,7 +267,7 @@ namespace Perspex.Controls.UnitTests.Primitives PerspexLocator.CurrentMutable .Bind().ToTransient() .Bind().ToFunc(() => globalStyles.Object) - .Bind().ToConstant(new Mock().Object) + .Bind().ToConstant(new WindowingPlatformMock()) .Bind().ToTransient(); return result; diff --git a/tests/Perspex.Controls.UnitTests/Primitives/WindowingPlatformMock.cs b/tests/Perspex.Controls.UnitTests/Primitives/WindowingPlatformMock.cs new file mode 100644 index 0000000000..bb879929a5 --- /dev/null +++ b/tests/Perspex.Controls.UnitTests/Primitives/WindowingPlatformMock.cs @@ -0,0 +1,21 @@ +using System; +using Moq; +using Perspex.Platform; + +namespace Perspex.Controls.UnitTests.Primitives +{ + class WindowingPlatformMock : IWindowingPlatform + { + public IWindowImpl CreateWindow() + { + return new Mock().Object; + } + + public IWindowImpl CreateDesignerFriendlyWindow() + { + throw new NotImplementedException(); + } + + public IPopupImpl CreatePopup() => new Mock().Object; + } +} \ No newline at end of file diff --git a/tests/Perspex.Controls.UnitTests/Utils/HotKeyManagerTests.cs b/tests/Perspex.Controls.UnitTests/Utils/HotKeyManagerTests.cs index 40949e624a..6cdcd81539 100644 --- a/tests/Perspex.Controls.UnitTests/Utils/HotKeyManagerTests.cs +++ b/tests/Perspex.Controls.UnitTests/Utils/HotKeyManagerTests.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Moq; using Perspex.Controls.Presenters; using Perspex.Controls.Templates; +using Perspex.Controls.UnitTests.Primitives; using Perspex.Input; using Perspex.Platform; using Perspex.Styling; @@ -20,11 +21,10 @@ namespace Perspex.Controls.UnitTests.Utils { using (PerspexLocator.EnterScope()) { - var windowImpl = new Mock(); var styler = new Mock(); PerspexLocator.CurrentMutable - .Bind().ToConstant(windowImpl.Object) + .Bind().ToConstant(new WindowingPlatformMock()) .Bind().ToConstant(styler.Object); var gesture1 = new KeyGesture {Key = Key.A, Modifiers = InputModifiers.Control}; From 27e1d4accbea0a41a0206d126c532dd3952adb06 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 27 Nov 2015 00:25:06 +0300 Subject: [PATCH 4/6] Fix for FullLayoutTests --- .../Primitives/WindowingPlatformMock.cs | 15 ++++++++++++--- tests/Perspex.Layout.UnitTests/FullLayoutTests.cs | 3 ++- .../Perspex.Layout.UnitTests.csproj | 4 ++++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/tests/Perspex.Controls.UnitTests/Primitives/WindowingPlatformMock.cs b/tests/Perspex.Controls.UnitTests/Primitives/WindowingPlatformMock.cs index bb879929a5..6dde6ef4d1 100644 --- a/tests/Perspex.Controls.UnitTests/Primitives/WindowingPlatformMock.cs +++ b/tests/Perspex.Controls.UnitTests/Primitives/WindowingPlatformMock.cs @@ -4,11 +4,20 @@ using Perspex.Platform; namespace Perspex.Controls.UnitTests.Primitives { - class WindowingPlatformMock : IWindowingPlatform + public class WindowingPlatformMock : IWindowingPlatform { + private readonly Func _windowImpl; + private readonly Func _popupImpl; + + public WindowingPlatformMock(Func windowImpl = null, Func popupImpl = null ) + { + _windowImpl = windowImpl; + _popupImpl = popupImpl; + } + public IWindowImpl CreateWindow() { - return new Mock().Object; + return _windowImpl?.Invoke() ?? new Mock().Object; } public IWindowImpl CreateDesignerFriendlyWindow() @@ -16,6 +25,6 @@ namespace Perspex.Controls.UnitTests.Primitives throw new NotImplementedException(); } - public IPopupImpl CreatePopup() => new Mock().Object; + public IPopupImpl CreatePopup() => _popupImpl?.Invoke() ?? new Mock().Object; } } \ No newline at end of file diff --git a/tests/Perspex.Layout.UnitTests/FullLayoutTests.cs b/tests/Perspex.Layout.UnitTests/FullLayoutTests.cs index 53a74dec19..88c0e53827 100644 --- a/tests/Perspex.Layout.UnitTests/FullLayoutTests.cs +++ b/tests/Perspex.Layout.UnitTests/FullLayoutTests.cs @@ -9,6 +9,7 @@ using Perspex.Controls; using Perspex.Controls.Presenters; using Perspex.Controls.Primitives; using Perspex.Controls.Templates; +using Perspex.Controls.UnitTests.Primitives; using Perspex.Diagnostics; using Perspex.Input; using Perspex.Platform; @@ -149,7 +150,7 @@ namespace Perspex.Layout.UnitTests .Bind().ToConstant(renderInterface) .Bind().ToConstant(renderManager) .Bind().ToConstant(new Styler()) - .Bind().ToConstant(windowImpl.Object); + .Bind().ToConstant(new WindowingPlatformMock(() => windowImpl.Object)); var theme = new DefaultTheme(); globalStyles.Setup(x => x.Styles).Returns(theme); diff --git a/tests/Perspex.Layout.UnitTests/Perspex.Layout.UnitTests.csproj b/tests/Perspex.Layout.UnitTests/Perspex.Layout.UnitTests.csproj index 15f1a5cc25..08e0e2c7a0 100644 --- a/tests/Perspex.Layout.UnitTests/Perspex.Layout.UnitTests.csproj +++ b/tests/Perspex.Layout.UnitTests/Perspex.Layout.UnitTests.csproj @@ -137,6 +137,10 @@ {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F} Perspex.Themes.Default + + {5ccb5571-7c30-4e7d-967d-0e2158ebd91f} + Perspex.Controls.UnitTests + From 6e33686ff6bfb6a6fba0ad9d1e0c7bc695ccf5ef Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 27 Nov 2015 14:44:44 +0300 Subject: [PATCH 5/6] CreateDesignerFriendlyWindow -> CreateEmbeddableWindow --- src/Android/Perspex.Android/AndroidPlatform.cs | 2 +- src/Gtk/Perspex.Gtk/GtkPlatform.cs | 2 +- src/Perspex.Controls/Platform/IWindowingPlatform.cs | 2 +- src/Perspex.Controls/Platform/PlatformManager.cs | 2 +- src/Windows/Perspex.Win32/Win32Platform.cs | 2 +- src/iOS/Perspex.iOS/PerspexAppDelegate.cs | 2 +- .../Primitives/WindowingPlatformMock.cs | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Android/Perspex.Android/AndroidPlatform.cs b/src/Android/Perspex.Android/AndroidPlatform.cs index 9276cba150..4b02a14aa0 100644 --- a/src/Android/Perspex.Android/AndroidPlatform.cs +++ b/src/Android/Perspex.Android/AndroidPlatform.cs @@ -57,7 +57,7 @@ namespace Perspex.Android return new WindowImpl(); } - public IWindowImpl CreateDesignerFriendlyWindow() + public IWindowImpl CreateEmbeddableWindow() { throw new NotImplementedException(); } diff --git a/src/Gtk/Perspex.Gtk/GtkPlatform.cs b/src/Gtk/Perspex.Gtk/GtkPlatform.cs index 014048854d..b8a6d5c511 100644 --- a/src/Gtk/Perspex.Gtk/GtkPlatform.cs +++ b/src/Gtk/Perspex.Gtk/GtkPlatform.cs @@ -90,7 +90,7 @@ namespace Perspex.Gtk return new WindowImpl(); } - public IWindowImpl CreateDesignerFriendlyWindow() + public IWindowImpl CreateEmbeddableWindow() { throw new NotSupportedException(); } diff --git a/src/Perspex.Controls/Platform/IWindowingPlatform.cs b/src/Perspex.Controls/Platform/IWindowingPlatform.cs index 99176b720e..5a12fbdeb2 100644 --- a/src/Perspex.Controls/Platform/IWindowingPlatform.cs +++ b/src/Perspex.Controls/Platform/IWindowingPlatform.cs @@ -9,7 +9,7 @@ namespace Perspex.Platform public interface IWindowingPlatform { IWindowImpl CreateWindow(); - IWindowImpl CreateDesignerFriendlyWindow(); + IWindowImpl CreateEmbeddableWindow(); IPopupImpl CreatePopup(); } } diff --git a/src/Perspex.Controls/Platform/PlatformManager.cs b/src/Perspex.Controls/Platform/PlatformManager.cs index 383eecd5c7..1e13b926c0 100644 --- a/src/Perspex.Controls/Platform/PlatformManager.cs +++ b/src/Perspex.Controls/Platform/PlatformManager.cs @@ -184,7 +184,7 @@ namespace Perspex.Controls.Platform { var platform = PerspexLocator.Current.GetService(); return - new WindowDecorator(s_designerMode ? platform.CreateDesignerFriendlyWindow() : platform.CreateWindow()); + new WindowDecorator(s_designerMode ? platform.CreateEmbeddableWindow() : platform.CreateWindow()); } public static IPopupImpl CreatePopup() diff --git a/src/Windows/Perspex.Win32/Win32Platform.cs b/src/Windows/Perspex.Win32/Win32Platform.cs index 5c8c475f17..89c6646b0c 100644 --- a/src/Windows/Perspex.Win32/Win32Platform.cs +++ b/src/Windows/Perspex.Win32/Win32Platform.cs @@ -163,7 +163,7 @@ namespace Perspex.Win32 return new WindowImpl(); } - public IWindowImpl CreateDesignerFriendlyWindow() + public IWindowImpl CreateEmbeddableWindow() { return new EmbeddedWindowImpl(); } diff --git a/src/iOS/Perspex.iOS/PerspexAppDelegate.cs b/src/iOS/Perspex.iOS/PerspexAppDelegate.cs index e526f3a69c..3a8c2e00df 100644 --- a/src/iOS/Perspex.iOS/PerspexAppDelegate.cs +++ b/src/iOS/Perspex.iOS/PerspexAppDelegate.cs @@ -61,7 +61,7 @@ namespace Perspex.iOS return _window; } - public IWindowImpl CreateDesignerFriendlyWindow() + public IWindowImpl CreateEmbeddableWindow() { throw new NotImplementedException(); } diff --git a/tests/Perspex.Controls.UnitTests/Primitives/WindowingPlatformMock.cs b/tests/Perspex.Controls.UnitTests/Primitives/WindowingPlatformMock.cs index 6dde6ef4d1..5169ebfa65 100644 --- a/tests/Perspex.Controls.UnitTests/Primitives/WindowingPlatformMock.cs +++ b/tests/Perspex.Controls.UnitTests/Primitives/WindowingPlatformMock.cs @@ -20,7 +20,7 @@ namespace Perspex.Controls.UnitTests.Primitives return _windowImpl?.Invoke() ?? new Mock().Object; } - public IWindowImpl CreateDesignerFriendlyWindow() + public IWindowImpl CreateEmbeddableWindow() { throw new NotImplementedException(); } From abd54620cd83c34b5084d0cb1a172eca41ff46b6 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 27 Nov 2015 14:45:37 +0300 Subject: [PATCH 6/6] Moved WindowingPlatformMock --- .../Perspex.Controls.UnitTests.csproj | 2 +- .../{Primitives => }/WindowingPlatformMock.cs | 2 +- tests/Perspex.Layout.UnitTests/FullLayoutTests.cs | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) rename tests/Perspex.Controls.UnitTests/{Primitives => }/WindowingPlatformMock.cs (94%) diff --git a/tests/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj b/tests/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj index c441eedf59..c19e639895 100644 --- a/tests/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj +++ b/tests/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj @@ -88,7 +88,7 @@ - + diff --git a/tests/Perspex.Controls.UnitTests/Primitives/WindowingPlatformMock.cs b/tests/Perspex.Controls.UnitTests/WindowingPlatformMock.cs similarity index 94% rename from tests/Perspex.Controls.UnitTests/Primitives/WindowingPlatformMock.cs rename to tests/Perspex.Controls.UnitTests/WindowingPlatformMock.cs index 5169ebfa65..989cb5f784 100644 --- a/tests/Perspex.Controls.UnitTests/Primitives/WindowingPlatformMock.cs +++ b/tests/Perspex.Controls.UnitTests/WindowingPlatformMock.cs @@ -2,7 +2,7 @@ using System; using Moq; using Perspex.Platform; -namespace Perspex.Controls.UnitTests.Primitives +namespace Perspex.Controls.UnitTests { public class WindowingPlatformMock : IWindowingPlatform { diff --git a/tests/Perspex.Layout.UnitTests/FullLayoutTests.cs b/tests/Perspex.Layout.UnitTests/FullLayoutTests.cs index 88c0e53827..3ca03c43b7 100644 --- a/tests/Perspex.Layout.UnitTests/FullLayoutTests.cs +++ b/tests/Perspex.Layout.UnitTests/FullLayoutTests.cs @@ -9,6 +9,7 @@ using Perspex.Controls; using Perspex.Controls.Presenters; using Perspex.Controls.Primitives; using Perspex.Controls.Templates; +using Perspex.Controls.UnitTests; using Perspex.Controls.UnitTests.Primitives; using Perspex.Diagnostics; using Perspex.Input;