Browse Source

Merge branch 'master' of https://github.com/Perspex/Perspex

pull/335/head
Steven Kirk 11 years ago
parent
commit
df0ba8a7e5
  1. 2
      docs/build.md
  2. 22
      src/Android/Perspex.Android/AndroidPlatform.cs
  3. 19
      src/Gtk/Perspex.Gtk/GtkPlatform.cs
  4. 4
      src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj
  5. 65
      src/Perspex.Application/Designer/Designer.cs
  6. 56
      src/Perspex.Application/Designer/DesignerApi.cs
  7. 19
      src/Perspex.Application/Perspex.Application.csproj
  8. 1
      src/Perspex.Base/Perspex.Base.csproj
  9. 0
      src/Perspex.Base/Platform/IAssetLoader.cs
  10. 1
      src/Perspex.Controls/Perspex.Controls.csproj
  11. 15
      src/Perspex.Controls/Platform/IWindowingPlatform.cs
  12. 27
      src/Perspex.Controls/Platform/PlatformManager.cs
  13. 35
      src/Windows/Perspex.Designer/AppHost/HostedAppModel.cs
  14. 78
      src/Windows/Perspex.Designer/AppHost/PerspexAppHost.cs
  15. 20
      src/Windows/Perspex.Designer/AppHost/WindowHost.cs
  16. 2
      src/Windows/Perspex.Designer/Comm/CommChannel.cs
  17. 28
      src/Windows/Perspex.Designer/InProcDesigner/InProcDesignerView.xaml
  18. 16
      src/Windows/Perspex.Designer/InProcDesigner/InProcDesignerView.xaml.cs
  19. 4
      src/Windows/Perspex.Designer/Perspex.Designer.csproj
  20. 19
      src/Windows/Perspex.Designer/Settings.cs
  21. 35
      src/Windows/Perspex.Win32/Win32Platform.cs
  22. 27
      src/iOS/Perspex.iOS/PerspexAppDelegate.cs
  23. 1
      tests/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj
  24. 2
      tests/Perspex.Controls.UnitTests/Primitives/PopupTests.cs
  25. 4
      tests/Perspex.Controls.UnitTests/Utils/HotKeyManagerTests.cs
  26. 30
      tests/Perspex.Controls.UnitTests/WindowingPlatformMock.cs
  27. 4
      tests/Perspex.Layout.UnitTests/FullLayoutTests.cs
  28. 4
      tests/Perspex.Layout.UnitTests/Perspex.Layout.UnitTests.csproj

2
docs/build.md

@ -12,7 +12,7 @@ Perspex.Gtk project in Visual Studio.
### Clone the Perspex repository ### Clone the Perspex repository
git clone https://github.com/grokys/Perspex.git git clone https://github.com/Perspex/Perspex.git
We currently need to build our own private version of ReactiveUI as it doesn't work on mono. This We currently need to build our own private version of ReactiveUI as it doesn't work on mono. This
is linked as a submodule in the git repository, so run: is linked as a submodule in the git repository, so run:

22
src/Android/Perspex.Android/AndroidPlatform.cs

@ -10,10 +10,11 @@ using Perspex.Shared.PlatformSupport;
using Perspex.Skia; using Perspex.Skia;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Perspex.Android.Platform.SkiaPlatform;
namespace Perspex.Android namespace Perspex.Android
{ {
public class AndroidPlatform : IPlatformSettings public class AndroidPlatform : IPlatformSettings, IWindowingPlatform
{ {
public static readonly AndroidPlatform Instance = new AndroidPlatform(); public static readonly AndroidPlatform Instance = new AndroidPlatform();
public Size DoubleClickSize => new Size(4, 4); public Size DoubleClickSize => new Size(4, 4);
@ -33,11 +34,11 @@ namespace Perspex.Android
.Bind<IPlatformSettings>().ToConstant(this) .Bind<IPlatformSettings>().ToConstant(this)
.Bind<IPlatformThreadingInterface>().ToConstant(new AndroidThreadingInterface()) .Bind<IPlatformThreadingInterface>().ToConstant(new AndroidThreadingInterface())
.Bind<ISystemDialogImpl>().ToTransient<SystemDialogImpl>() .Bind<ISystemDialogImpl>().ToTransient<SystemDialogImpl>()
.Bind<ITopLevelRenderer>().ToTransient<AndroidTopLevelRenderer>(); .Bind<ITopLevelRenderer>().ToTransient<AndroidTopLevelRenderer>()
.Bind<IWindowingPlatform>().ToConstant(this);
SkiaPlatform.Initialize(); SkiaPlatform.Initialize();
Application.RegisterPlatformCallback(() => { }); Application.RegisterPlatformCallback(() => { });
PerspexLocator.CurrentMutable.Bind<IWindowImpl>().ToSingleton<Platform.SkiaPlatform.MainWindowImpl>();
_scalingFactor = global::Android.App.Application.Context.Resources.DisplayMetrics.ScaledDensity; _scalingFactor = global::Android.App.Application.Context.Resources.DisplayMetrics.ScaledDensity;
@ -50,5 +51,20 @@ namespace Perspex.Android
{ {
SharedPlatform.Register(applicationType.Assembly); SharedPlatform.Register(applicationType.Assembly);
} }
public IWindowImpl CreateWindow()
{
return new WindowImpl();
}
public IWindowImpl CreateEmbeddableWindow()
{
throw new NotImplementedException();
}
public IPopupImpl CreatePopup()
{
throw new NotImplementedException();
}
} }
} }

19
src/Gtk/Perspex.Gtk/GtkPlatform.cs

@ -14,7 +14,7 @@ namespace Perspex.Gtk
{ {
using Gtk = global::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 readonly GtkPlatform s_instance = new GtkPlatform();
private static Thread _uiThread; private static Thread _uiThread;
@ -33,8 +33,7 @@ namespace Perspex.Gtk
public static void Initialize() public static void Initialize()
{ {
PerspexLocator.CurrentMutable PerspexLocator.CurrentMutable
.Bind<IWindowImpl>().ToTransient<WindowImpl>() .Bind<IWindowingPlatform>().ToConstant(s_instance)
.Bind<IPopupImpl>().ToTransient<PopupImpl>()
.Bind<IClipboard>().ToSingleton<ClipboardImpl>() .Bind<IClipboard>().ToSingleton<ClipboardImpl>()
.Bind<IStandardCursorFactory>().ToConstant(CursorFactory.Instance) .Bind<IStandardCursorFactory>().ToConstant(CursorFactory.Instance)
.Bind<IKeyboardDevice>().ToConstant(GtkKeyboardDevice.Instance) .Bind<IKeyboardDevice>().ToConstant(GtkKeyboardDevice.Instance)
@ -86,5 +85,19 @@ namespace Perspex.Gtk
public bool CurrentThreadIsLoopThread => Thread.CurrentThread == _uiThread; public bool CurrentThreadIsLoopThread => Thread.CurrentThread == _uiThread;
public event Action Signaled; public event Action Signaled;
public IWindowImpl CreateWindow()
{
return new WindowImpl();
}
public IWindowImpl CreateEmbeddableWindow()
{
throw new NotSupportedException();
}
public IPopupImpl CreatePopup()
{
return new PopupImpl();
}
} }
} }

4
src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj

@ -272,10 +272,6 @@
<Project>{D211E587-D8BC-45B9-95A4-F297C8FA5200}</Project> <Project>{D211E587-D8BC-45B9-95A4-F297C8FA5200}</Project>
<Name>Perspex.Animation</Name> <Name>Perspex.Animation</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\..\Perspex.Application\Perspex.Application.csproj">
<Project>{799A7BB5-3C2C-48B6-85A7-406A12C420DA}</Project>
<Name>Perspex.Application</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.Base\Perspex.Base.csproj"> <ProjectReference Include="..\..\Perspex.Base\Perspex.Base.csproj">
<Project>{B09B78D8-9B26-48B0-9149-D64A2F120F3F}</Project> <Project>{B09B78D8-9B26-48B0-9149-D64A2F120F3F}</Project>
<Name>Perspex.Base</Name> <Name>Perspex.Base</Name>

65
src/Perspex.Application/Designer/Designer.cs

@ -0,0 +1,65 @@
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<string, object> shared)
{
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)
{
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();
}
}
}

56
src/Perspex.Application/Designer/DesignerApi.cs

@ -0,0 +1,56 @@
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<string, object> _inner;
public DesignerApi(Dictionary<string, object> 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<string> UpdateXaml
{
get { return (Action<string>) Get(); }
set {Set(value); }
}
public Action OnResize
{
get { return (Action) Get(); }
set { Set(value);}
}
public Action<IntPtr> OnWindowCreated
{
set { Set(value); }
get { return (Action<IntPtr>) Get(); }
}
public Action<double> SetScalingFactor
{
set { Set(value);}
get { return (Action<double>) Get(); }
}
}
}

19
src/Perspex.Application/Perspex.Application.csproj

@ -39,6 +39,18 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<!-- A reference to the entire .NET Framework is automatically included --> <!-- A reference to the entire .NET Framework is automatically included -->
<ProjectReference Include="..\Markup\Perspex.Markup.Xaml\Perspex.Markup.Xaml.csproj">
<Project>{3e53a01a-b331-47f3-b828-4a5717e77a24}</Project>
<Name>Perspex.Markup.Xaml</Name>
</ProjectReference>
<ProjectReference Include="..\Markup\Perspex.Markup\Perspex.Markup.csproj">
<Project>{6417e941-21bc-467b-a771-0de389353ce6}</Project>
<Name>Perspex.Markup</Name>
</ProjectReference>
<ProjectReference Include="..\Perspex.Animation\Perspex.Animation.csproj">
<Project>{d211e587-d8bc-45b9-95a4-f297c8fa5200}</Project>
<Name>Perspex.Animation</Name>
</ProjectReference>
<ProjectReference Include="..\Perspex.Base\Perspex.Base.csproj"> <ProjectReference Include="..\Perspex.Base\Perspex.Base.csproj">
<Project>{B09B78D8-9B26-48B0-9149-D64A2F120F3F}</Project> <Project>{B09B78D8-9B26-48B0-9149-D64A2F120F3F}</Project>
<Name>Perspex.Base</Name> <Name>Perspex.Base</Name>
@ -67,13 +79,18 @@
<Project>{F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}</Project> <Project>{F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}</Project>
<Name>Perspex.Styling</Name> <Name>Perspex.Styling</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\Perspex.Themes.Default\Perspex.Themes.Default.csproj">
<Project>{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}</Project>
<Name>Perspex.Themes.Default</Name>
</ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="..\Shared\SharedAssemblyInfo.cs"> <Compile Include="..\Shared\SharedAssemblyInfo.cs">
<Link>Properties\SharedAssemblyInfo.cs</Link> <Link>Properties\SharedAssemblyInfo.cs</Link>
</Compile> </Compile>
<Compile Include="Application.cs" /> <Compile Include="Application.cs" />
<Compile Include="Platform\IAssetLoader.cs" /> <Compile Include="Designer\Designer.cs" />
<Compile Include="Designer\DesignerApi.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

1
src/Perspex.Base/Perspex.Base.csproj

@ -53,6 +53,7 @@
<Compile Include="PerspexObjectExtensions.cs" /> <Compile Include="PerspexObjectExtensions.cs" />
<Compile Include="PerspexPropertyRegistry.cs" /> <Compile Include="PerspexPropertyRegistry.cs" />
<Compile Include="PerspexProperty`1.cs" /> <Compile Include="PerspexProperty`1.cs" />
<Compile Include="Platform\IAssetLoader.cs" />
<Compile Include="Platform\IPclPlatformWrapper.cs" /> <Compile Include="Platform\IPclPlatformWrapper.cs" />
<Compile Include="BindingPriority.cs" /> <Compile Include="BindingPriority.cs" />
<Compile Include="PriorityBindingEntry.cs" /> <Compile Include="PriorityBindingEntry.cs" />

0
src/Perspex.Application/Platform/IAssetLoader.cs → src/Perspex.Base/Platform/IAssetLoader.cs

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

@ -44,6 +44,7 @@
<Compile Include="DockPanel.cs" /> <Compile Include="DockPanel.cs" />
<Compile Include="HotkeyManager.cs" /> <Compile Include="HotkeyManager.cs" />
<Compile Include="Platform\ITopLevelRenderer.cs" /> <Compile Include="Platform\ITopLevelRenderer.cs" />
<Compile Include="Platform\IWindowingPlatform.cs" />
<Compile Include="Platform\PlatformManager.cs" /> <Compile Include="Platform\PlatformManager.cs" />
<Compile Include="SelectionMode.cs" /> <Compile Include="SelectionMode.cs" />
<Compile Include="Separator.cs" /> <Compile Include="Separator.cs" />

15
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 CreateEmbeddableWindow();
IPopupImpl CreatePopup();
}
}

27
src/Perspex.Controls/Platform/PlatformManager.cs

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reactive.Disposables;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Perspex.Input; using Perspex.Input;
@ -17,6 +18,9 @@ namespace Perspex.Controls.Platform
static IPlatformSettings GetSettings() static IPlatformSettings GetSettings()
=> PerspexLocator.Current.GetService<IPlatformSettings>(); => PerspexLocator.Current.GetService<IPlatformSettings>();
static bool s_designerMode;
private static double _designerScalingFactor = 1;
public static IRenderTarget CreateRenderTarget(ITopLevelImpl window) public static IRenderTarget CreateRenderTarget(ITopLevelImpl window)
{ {
return return
@ -24,6 +28,19 @@ namespace Perspex.Controls.Platform
PerspexLocator.Current.GetService<IPlatformRenderInterface>().CreateRenderer(window.Handle), window); PerspexLocator.Current.GetService<IPlatformRenderInterface>().CreateRenderer(window.Handle), window);
} }
public static IDisposable DesignerMode()
{
s_designerMode = true;
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 class RenderTargetDecorator : IRenderTarget
{ {
@ -45,7 +62,7 @@ namespace Perspex.Controls.Platform
{ {
var cs = _window.ClientSize; var cs = _window.ClientSize;
var ctx = _target.CreateDrawingContext(); var ctx = _target.CreateDrawingContext();
var factor = GetSettings()?.RenderScalingFactor ?? 1; var factor = RenderScalingFactor;
if (factor != 1) if (factor != 1)
{ {
ctx.PushPostTransform(Matrix.CreateScale(factor, factor)); ctx.PushPostTransform(Matrix.CreateScale(factor, factor));
@ -62,7 +79,7 @@ namespace Perspex.Controls.Platform
private readonly IPopupImpl _popup; private readonly IPopupImpl _popup;
public ITopLevelImpl TopLevel => _tl; public ITopLevelImpl TopLevel => _tl;
double ScalingFactor => GetSettings()?.LayoutScalingFactor ?? 1; double ScalingFactor => LayoutScalingFactor;
public WindowDecorator(ITopLevelImpl tl) public WindowDecorator(ITopLevelImpl tl)
{ {
@ -165,12 +182,14 @@ namespace Perspex.Controls.Platform
public static IWindowImpl CreateWindow() public static IWindowImpl CreateWindow()
{ {
return new WindowDecorator(PerspexLocator.Current.GetService<IWindowImpl>()); var platform = PerspexLocator.Current.GetService<IWindowingPlatform>();
return
new WindowDecorator(s_designerMode ? platform.CreateEmbeddableWindow() : platform.CreateWindow());
} }
public static IPopupImpl CreatePopup() public static IPopupImpl CreatePopup()
{ {
return new WindowDecorator(PerspexLocator.Current.GetService<IPopupImpl>()); return new WindowDecorator(PerspexLocator.Current.GetService<IWindowingPlatform>().CreatePopup());
} }
} }
} }

35
src/Windows/Perspex.Designer/AppHost/HostedAppModel.cs

@ -5,16 +5,24 @@ using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Media;
using JetBrains.Annotations; using JetBrains.Annotations;
namespace Perspex.Designer.AppHost namespace Perspex.Designer.AppHost
{ {
public class HostedAppModel : INotifyPropertyChanged public class HostedAppModel : INotifyPropertyChanged
{ {
private readonly PerspexAppHost _host;
private IntPtr _nativeWindowHandle; private IntPtr _nativeWindowHandle;
private string _error; private string _error;
private string _errorDetails; private string _errorDetails;
internal HostedAppModel(PerspexAppHost host)
{
_host = host;
Background = Settings.Background;
}
public IntPtr NativeWindowHandle public IntPtr NativeWindowHandle
{ {
get { return _nativeWindowHandle; } get { return _nativeWindowHandle; }
@ -48,12 +56,39 @@ namespace Perspex.Designer.AppHost
} }
} }
public string Background
{
get { return _background; }
set
{
if (value == _background) return;
_background = value;
OnPropertyChanged();
}
}
public IReadOnlyList<double> AvailableScalingFactors => new List<double>() {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) public void SetError(string error, string details = null)
{ {
Error = error; Error = error;
ErrorDetails = details; ErrorDetails = details;
} }
double _currentScalingFactor = 1;
private string _color;
private string _background;
public event PropertyChangedEventHandler PropertyChanged; public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator] [NotifyPropertyChangedInvocator]

78
src/Windows/Perspex.Designer/AppHost/PerspexAppHost.cs

@ -18,17 +18,17 @@ namespace Perspex.Designer.AppHost
class PerspexAppHost class PerspexAppHost
{ {
private string _appDir; private string _appDir;
private CommChannel _comm; private readonly CommChannel _comm;
private string _lastXaml; private string _lastXaml;
private string _currentXaml; private string _currentXaml;
private Func<Stream, object> _xamlReader;
private bool _initSuccess; private bool _initSuccess;
private HostedAppModel _appModel = new HostedAppModel(); private HostedAppModel _appModel;
private Control _window; private Control _window;
public PerspexAppHost(CommChannel channel) public PerspexAppHost(CommChannel channel)
{ {
_comm = channel; _comm = channel;
_appModel = new HostedAppModel(this);
} }
public void Start() public void Start()
@ -92,8 +92,6 @@ namespace Perspex.Designer.AppHost
PerspexDesignerMetadata BuildMetadata(List<Assembly> asms, Type xmlNsAttr) PerspexDesignerMetadata BuildMetadata(List<Assembly> asms, Type xmlNsAttr)
{ {
var rv = new PerspexDesignerMetadata() var rv = new PerspexDesignerMetadata()
{ {
@ -200,34 +198,10 @@ namespace Perspex.Designer.AppHost
log("Looking up Perspex types"); log("Looking up Perspex types");
BuildMetadataAndSendMessageAsync(asms); BuildMetadataAndSendMessageAsync(asms);
var syncContext = LookupType("Perspex.Threading.PerspexSynchronizationContext"); log("Initializing built-in designer");
syncContext.GetProperty("AutoInstall", BindingFlags.Public | BindingFlags.Static).SetValue(null, false); var dic = new Dictionary<string, object>();
Api = new DesignerApi(dic) {OnResize = OnResize, OnWindowCreated = OnWindowCreated};
var app = Activator.CreateInstance(LookupType("Perspex.Application")); LookupStaticMethod("Perspex.Designer.Designer", "Init").Invoke(null, new object[] {dic});
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);
_window = new Control _window = new Control
{ {
@ -242,15 +216,19 @@ namespace Perspex.Designer.AppHost
}; };
_window.CreateControl(); _window.CreateControl();
new Timer {Interval = 10, Enabled = true}.Tick += delegate
{
dispatcher.RunJobs();
};
new Timer {Interval = 200, Enabled = true}.Tick += delegate { XamlUpdater(); }; new Timer {Interval = 200, Enabled = true}.Tick += delegate { XamlUpdater(); };
_comm.SendMessage(new WindowCreatedMessage(_window.Handle)); _comm.SendMessage(new WindowCreatedMessage(_window.Handle));
_initSuccess = true; _initSuccess = true;
} }
private void OnWindowCreated(IntPtr hWnd)
{
_appModel.NativeWindowHandle = hWnd;
}
public DesignerApi Api { get; set; }
bool ValidateXml(string xml) bool ValidateXml(string xml)
{ {
@ -269,6 +247,11 @@ namespace Perspex.Designer.AppHost
return true; return true;
} }
private void OnResize()
{
}
void XamlUpdater() void XamlUpdater()
{ {
if (!_initSuccess) if (!_initSuccess)
@ -282,27 +265,10 @@ namespace Perspex.Designer.AppHost
_appModel.SetError("Invalid markup"); _appModel.SetError("Invalid markup");
return; return;
} }
try try
{ {
const string windowType = "Perspex.Controls.Window"; Api.UpdateXaml(_currentXaml);
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;
}
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); _appModel.SetError(null);
} }
catch (Exception e) catch (Exception e)
@ -310,6 +276,8 @@ namespace Perspex.Designer.AppHost
_appModel.SetError("XAML load error", e.ToString()); _appModel.SetError("XAML load error", e.ToString());
} }
} }
private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{ {

20
src/Windows/Perspex.Designer/AppHost/WindowHost.cs

@ -20,7 +20,19 @@ namespace Perspex.Designer.AppHost
Text = "ScrollableArea"; Text = "ScrollableArea";
Controls.Add(_windowHost); Controls.Add(_windowHost);
_windowHost.Anchor = AnchorStyles.None; _windowHost.Anchor = AnchorStyles.None;
_timer.Tick += delegate { FixWindow(); }; _timer.Tick += delegate
{
ReloadSettings();
FixWindow();
};
}
private void ReloadSettings()
{
var bkg = Settings.Background;
var color = System.Drawing.ColorTranslator.FromHtml(bkg);
if (BackColor != color)
BackColor = color;
} }
private Control _windowHost = new Control() {Text = "WindowWrapper"}; private Control _windowHost = new Control() {Text = "WindowWrapper"};
@ -43,6 +55,12 @@ namespace Perspex.Designer.AppHost
base.WndProc(ref m); base.WndProc(ref m);
} }
protected override void OnPaint(PaintEventArgs e)
{
using (var b = new SolidBrush(BackColor))
e.Graphics.FillRectangle(b, e.ClipRectangle);
}
void FixPosition() void FixPosition()
{ {
var newScrollSize = new Size(_desiredWidth, _desiredHeight); var newScrollSize = new Size(_desiredWidth, _desiredHeight);

2
src/Windows/Perspex.Designer/Comm/CommChannel.cs

@ -13,7 +13,7 @@ using System.Windows.Threading;
namespace Perspex.Designer.Comm namespace Perspex.Designer.Comm
{ {
internal class CommChannel : IDisposable class CommChannel : IDisposable
{ {
private readonly BinaryReader _input; private readonly BinaryReader _input;
private readonly BinaryWriter _output; private readonly BinaryWriter _output;

28
src/Windows/Perspex.Designer/InProcDesigner/InProcDesignerView.xaml

@ -4,17 +4,31 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:appHost="clr-namespace:Perspex.Designer.AppHost" xmlns:appHost="clr-namespace:Perspex.Designer.AppHost"
xmlns:system="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" d:DataContext="{d:DesignInstance appHost:HostedAppModel}"> d:DesignHeight="300" d:DesignWidth="300" d:DataContext="{d:DesignInstance appHost:HostedAppModel}">
<DockPanel> <DockPanel>
<Border x:Name="ErrorPanel" DockPanel.Dock="Bottom" BorderBrush="Red" BorderThickness="3" Padding="3"> <StackPanel Orientation="Horizontal" DockPanel.Dock="Bottom">
<StackPanel Orientation="Horizontal"> <ComboBox ItemsSource="{Binding AvailableScalingFactors}" SelectedItem="{Binding CurrentScalingFactor, Mode=TwoWay}">
<TextBlock Text="{Binding Error}" FontSize="16"/> <ComboBox.ItemTemplate>
<TextBlock x:Name="DetailsBlock" FontSize="16"> <DataTemplate DataType="{x:Type system:Double}">
<TextBlock><Run Text="{Binding .}"/>00%</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Rectangle Cursor="Hand" Stroke="Black" Width="{Binding RelativeSource={RelativeSource Self}, Path=ActualHeight}" Fill="{Binding Background}"
Margin="3" MouseDown="ColorPicker_OnClick"/>
<Border x:Name="ErrorPanel" BorderBrush="Red" BorderThickness="3" Padding="3">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Error}" FontSize="16"/>
<TextBlock x:Name="DetailsBlock" FontSize="16">
<Run> (</Run><Hyperlink Click="Hyperlink_OnClick">View details</Hyperlink><Run>)</Run> <Run> (</Run><Hyperlink Click="Hyperlink_OnClick">View details</Hyperlink><Run>)</Run>
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
</Border> </Border>
</StackPanel>
<WindowsFormsHost x:Name="WindowHostControl"/> <WindowsFormsHost x:Name="WindowHostControl"/>
</DockPanel> </DockPanel>
</UserControl> </UserControl>

16
src/Windows/Perspex.Designer/InProcDesigner/InProcDesignerView.xaml.cs

@ -1,18 +1,21 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
using System.Windows.Documents; using System.Windows.Documents;
using System.Windows.Forms;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using System.Windows.Navigation; using System.Windows.Navigation;
using System.Windows.Shapes; using System.Windows.Shapes;
using Perspex.Designer.AppHost; using Perspex.Designer.AppHost;
using TextBox = System.Windows.Controls.TextBox;
using UserControl = System.Windows.Controls.UserControl;
namespace Perspex.Designer.InProcDesigner namespace Perspex.Designer.InProcDesigner
{ {
@ -80,5 +83,16 @@ namespace Perspex.Designer.InProcDesigner
}; };
wnd.ShowDialog(); wnd.ShowDialog();
} }
private void ColorPicker_OnClick(object sender, MouseButtonEventArgs e)
{
var dlg = new ColorDialog() {Color = ColorTranslator.FromHtml(Settings.Background)};
if (dlg.ShowDialog(_host) == DialogResult.OK)
{
var color = ColorTranslator.ToHtml(dlg.Color);
_appModel.Background = color;
Settings.Background = color;
}
}
} }
} }

4
src/Windows/Perspex.Designer/Perspex.Designer.csproj

@ -67,6 +67,9 @@
<Reference Include="WindowsFormsIntegration" /> <Reference Include="WindowsFormsIntegration" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="..\..\Perspex.Application\Designer\DesignerApi.cs">
<Link>AppHost\DesignerApi.cs</Link>
</Compile>
<Compile Include="App.xaml.cs"> <Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon> <DependentUpon>App.xaml</DependentUpon>
</Compile> </Compile>
@ -94,6 +97,7 @@
</Compile> </Compile>
<Compile Include="Program.cs" /> <Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Settings.cs" />
<Compile Include="WinApi.cs" /> <Compile Include="WinApi.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

19
src/Windows/Perspex.Designer/Settings.cs

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Win32;
namespace Perspex.Designer
{
static class Settings
{
static readonly string Root = @"HKEY_CURRENT_USER\Software\PerspexUI\Designer";
public static string Background
{
get { return Registry.GetValue(Root, "Background", "#f3f3f3")?.ToString() ?? "#f3f3f3"; }
set { Registry.SetValue(Root, "Background", value); }
}
}
}

35
src/Windows/Perspex.Win32/Win32Platform.cs

@ -18,7 +18,7 @@ using Perspex.Win32.Interop;
namespace Perspex.Win32 namespace Perspex.Win32
{ {
public class Win32Platform : IPlatformThreadingInterface, IPlatformSettings public class Win32Platform : IPlatformThreadingInterface, IPlatformSettings, IWindowingPlatform
{ {
private static readonly Win32Platform s_instance = new Win32Platform(); private static readonly Win32Platform s_instance = new Win32Platform();
private static Thread _uiThread; private static Thread _uiThread;
@ -42,34 +42,22 @@ namespace Perspex.Win32
public double RenderScalingFactor { get; } = 1; public double RenderScalingFactor { get; } = 1;
public double LayoutScalingFactor { get; } = 1; public double LayoutScalingFactor { get; } = 1;
private static void InitializeInternal() public static void Initialize()
{ {
PerspexLocator.CurrentMutable PerspexLocator.CurrentMutable
.Bind<IPopupImpl>().ToTransient<PopupImpl>()
.Bind<IClipboard>().ToSingleton<ClipboardImpl>() .Bind<IClipboard>().ToSingleton<ClipboardImpl>()
.Bind<IStandardCursorFactory>().ToConstant(CursorFactory.Instance) .Bind<IStandardCursorFactory>().ToConstant(CursorFactory.Instance)
.Bind<IKeyboardDevice>().ToConstant(WindowsKeyboardDevice.Instance) .Bind<IKeyboardDevice>().ToConstant(WindowsKeyboardDevice.Instance)
.Bind<IMouseDevice>().ToConstant(WindowsMouseDevice.Instance) .Bind<IMouseDevice>().ToConstant(WindowsMouseDevice.Instance)
.Bind<IPlatformSettings>().ToConstant(s_instance) .Bind<IPlatformSettings>().ToConstant(s_instance)
.Bind<IPlatformThreadingInterface>().ToConstant(s_instance) .Bind<IPlatformThreadingInterface>().ToConstant(s_instance)
.Bind<ISystemDialogImpl>().ToSingleton<SystemDialogImpl>(); .Bind<ISystemDialogImpl>().ToSingleton<SystemDialogImpl>()
.Bind<IWindowingPlatform>().ToConstant(s_instance);
SharedPlatform.Register(); SharedPlatform.Register();
_uiThread = Thread.CurrentThread; _uiThread = Thread.CurrentThread;
} }
public static void Initialize()
{
PerspexLocator.CurrentMutable.Bind<IWindowImpl>().ToTransient<WindowImpl>();
InitializeInternal();
}
public static void InitializeEmbedded()
{
PerspexLocator.CurrentMutable.Bind<IWindowImpl>().ToTransient<EmbeddedWindowImpl>();
InitializeInternal();
}
public bool HasMessages() public bool HasMessages()
{ {
UnmanagedMethods.MSG msg; UnmanagedMethods.MSG msg;
@ -169,5 +157,20 @@ namespace Perspex.Win32
throw new Win32Exception(); throw new Win32Exception();
} }
} }
public IWindowImpl CreateWindow()
{
return new WindowImpl();
}
public IWindowImpl CreateEmbeddableWindow()
{
return new EmbeddedWindowImpl();
}
public IPopupImpl CreatePopup()
{
return new PopupImpl();
}
} }
} }

27
src/iOS/Perspex.iOS/PerspexAppDelegate.cs

@ -42,9 +42,34 @@ namespace Perspex.iOS
.Bind<IMouseDevice>().ToConstant(MouseDevice) .Bind<IMouseDevice>().ToConstant(MouseDevice)
.Bind<IPlatformSettings>().ToSingleton<PlatformSettings>() .Bind<IPlatformSettings>().ToSingleton<PlatformSettings>()
.Bind<IPlatformThreadingInterface>().ToConstant(PlatformThreadingInterface.Instance) .Bind<IPlatformThreadingInterface>().ToConstant(PlatformThreadingInterface.Instance)
.Bind<IWindowImpl>().ToConstant(controller.PerspexView); .Bind<IWindowingPlatform>().ToConstant(new WindowingPlatform(controller.PerspexView));
SkiaPlatform.Initialize(); SkiaPlatform.Initialize();
}); });
} }
class WindowingPlatform : IWindowingPlatform
{
private readonly IWindowImpl _window;
public WindowingPlatform(IWindowImpl window)
{
_window = window;
}
public IWindowImpl CreateWindow()
{
return _window;
}
public IWindowImpl CreateEmbeddableWindow()
{
throw new NotImplementedException();
}
public IPopupImpl CreatePopup()
{
throw new NotImplementedException();
}
}
} }
} }

1
tests/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj

@ -88,6 +88,7 @@
<Compile Include="BorderTests.cs" /> <Compile Include="BorderTests.cs" />
<Compile Include="ListBoxTests_Single.cs" /> <Compile Include="ListBoxTests_Single.cs" />
<Compile Include="Primitives\SelectingItemsControlTests_Multiple.cs" /> <Compile Include="Primitives\SelectingItemsControlTests_Multiple.cs" />
<Compile Include="WindowingPlatformMock.cs" />
<Compile Include="TreeViewTests.cs" /> <Compile Include="TreeViewTests.cs" />
<Compile Include="Mixins\SelectableMixinTests.cs" /> <Compile Include="Mixins\SelectableMixinTests.cs" />
<Compile Include="StackPanelTests.cs" /> <Compile Include="StackPanelTests.cs" />

2
tests/Perspex.Controls.UnitTests/Primitives/PopupTests.cs

@ -267,7 +267,7 @@ namespace Perspex.Controls.UnitTests.Primitives
PerspexLocator.CurrentMutable PerspexLocator.CurrentMutable
.Bind<ILayoutManager>().ToTransient<LayoutManager>() .Bind<ILayoutManager>().ToTransient<LayoutManager>()
.Bind<IGlobalStyles>().ToFunc(() => globalStyles.Object) .Bind<IGlobalStyles>().ToFunc(() => globalStyles.Object)
.Bind<IPopupImpl>().ToConstant(new Mock<IPopupImpl>().Object) .Bind<IWindowingPlatform>().ToConstant(new WindowingPlatformMock())
.Bind<IStyler>().ToTransient<Styler>(); .Bind<IStyler>().ToTransient<Styler>();
return result; return result;

4
tests/Perspex.Controls.UnitTests/Utils/HotKeyManagerTests.cs

@ -6,6 +6,7 @@ using System.Threading.Tasks;
using Moq; using Moq;
using Perspex.Controls.Presenters; using Perspex.Controls.Presenters;
using Perspex.Controls.Templates; using Perspex.Controls.Templates;
using Perspex.Controls.UnitTests.Primitives;
using Perspex.Input; using Perspex.Input;
using Perspex.Platform; using Perspex.Platform;
using Perspex.Styling; using Perspex.Styling;
@ -20,11 +21,10 @@ namespace Perspex.Controls.UnitTests.Utils
{ {
using (PerspexLocator.EnterScope()) using (PerspexLocator.EnterScope())
{ {
var windowImpl = new Mock<IWindowImpl>();
var styler = new Mock<Styler>(); var styler = new Mock<Styler>();
PerspexLocator.CurrentMutable PerspexLocator.CurrentMutable
.Bind<IWindowImpl>().ToConstant(windowImpl.Object) .Bind<IWindowingPlatform>().ToConstant(new WindowingPlatformMock())
.Bind<IStyler>().ToConstant(styler.Object); .Bind<IStyler>().ToConstant(styler.Object);
var gesture1 = new KeyGesture {Key = Key.A, Modifiers = InputModifiers.Control}; var gesture1 = new KeyGesture {Key = Key.A, Modifiers = InputModifiers.Control};

30
tests/Perspex.Controls.UnitTests/WindowingPlatformMock.cs

@ -0,0 +1,30 @@
using System;
using Moq;
using Perspex.Platform;
namespace Perspex.Controls.UnitTests
{
public class WindowingPlatformMock : IWindowingPlatform
{
private readonly Func<IWindowImpl> _windowImpl;
private readonly Func<IPopupImpl> _popupImpl;
public WindowingPlatformMock(Func<IWindowImpl> windowImpl = null, Func<IPopupImpl> popupImpl = null )
{
_windowImpl = windowImpl;
_popupImpl = popupImpl;
}
public IWindowImpl CreateWindow()
{
return _windowImpl?.Invoke() ?? new Mock<IWindowImpl>().Object;
}
public IWindowImpl CreateEmbeddableWindow()
{
throw new NotImplementedException();
}
public IPopupImpl CreatePopup() => _popupImpl?.Invoke() ?? new Mock<IPopupImpl>().Object;
}
}

4
tests/Perspex.Layout.UnitTests/FullLayoutTests.cs

@ -9,6 +9,8 @@ using Perspex.Controls;
using Perspex.Controls.Presenters; using Perspex.Controls.Presenters;
using Perspex.Controls.Primitives; using Perspex.Controls.Primitives;
using Perspex.Controls.Templates; using Perspex.Controls.Templates;
using Perspex.Controls.UnitTests;
using Perspex.Controls.UnitTests.Primitives;
using Perspex.Diagnostics; using Perspex.Diagnostics;
using Perspex.Input; using Perspex.Input;
using Perspex.Platform; using Perspex.Platform;
@ -149,7 +151,7 @@ namespace Perspex.Layout.UnitTests
.Bind<IPlatformRenderInterface>().ToConstant(renderInterface) .Bind<IPlatformRenderInterface>().ToConstant(renderInterface)
.Bind<IRenderQueueManager>().ToConstant(renderManager) .Bind<IRenderQueueManager>().ToConstant(renderManager)
.Bind<IStyler>().ToConstant(new Styler()) .Bind<IStyler>().ToConstant(new Styler())
.Bind<IWindowImpl>().ToConstant(windowImpl.Object); .Bind<IWindowingPlatform>().ToConstant(new WindowingPlatformMock(() => windowImpl.Object));
var theme = new DefaultTheme(); var theme = new DefaultTheme();
globalStyles.Setup(x => x.Styles).Returns(theme); globalStyles.Setup(x => x.Styles).Returns(theme);

4
tests/Perspex.Layout.UnitTests/Perspex.Layout.UnitTests.csproj

@ -137,6 +137,10 @@
<Project>{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}</Project> <Project>{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}</Project>
<Name>Perspex.Themes.Default</Name> <Name>Perspex.Themes.Default</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\Perspex.Controls.UnitTests\Perspex.Controls.UnitTests.csproj">
<Project>{5ccb5571-7c30-4e7d-967d-0e2158ebd91f}</Project>
<Name>Perspex.Controls.UnitTests</Name>
</ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="app.config" /> <None Include="app.config" />

Loading…
Cancel
Save