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
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
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 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<IPlatformSettings>().ToConstant(this)
.Bind<IPlatformThreadingInterface>().ToConstant(new AndroidThreadingInterface())
.Bind<ISystemDialogImpl>().ToTransient<SystemDialogImpl>()
.Bind<ITopLevelRenderer>().ToTransient<AndroidTopLevelRenderer>();
.Bind<ITopLevelRenderer>().ToTransient<AndroidTopLevelRenderer>()
.Bind<IWindowingPlatform>().ToConstant(this);
SkiaPlatform.Initialize();
Application.RegisterPlatformCallback(() => { });
PerspexLocator.CurrentMutable.Bind<IWindowImpl>().ToSingleton<Platform.SkiaPlatform.MainWindowImpl>();
_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 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;
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<IWindowImpl>().ToTransient<WindowImpl>()
.Bind<IPopupImpl>().ToTransient<PopupImpl>()
.Bind<IWindowingPlatform>().ToConstant(s_instance)
.Bind<IClipboard>().ToSingleton<ClipboardImpl>()
.Bind<IStandardCursorFactory>().ToConstant(CursorFactory.Instance)
.Bind<IKeyboardDevice>().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 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>
<Name>Perspex.Animation</Name>
</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">
<Project>{B09B78D8-9B26-48B0-9149-D64A2F120F3F}</Project>
<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>
<ItemGroup>
<!-- 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">
<Project>{B09B78D8-9B26-48B0-9149-D64A2F120F3F}</Project>
<Name>Perspex.Base</Name>
@ -67,13 +79,18 @@
<Project>{F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}</Project>
<Name>Perspex.Styling</Name>
</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>
<Compile Include="..\Shared\SharedAssemblyInfo.cs">
<Link>Properties\SharedAssemblyInfo.cs</Link>
</Compile>
<Compile Include="Application.cs" />
<Compile Include="Platform\IAssetLoader.cs" />
<Compile Include="Designer\Designer.cs" />
<Compile Include="Designer\DesignerApi.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>

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

@ -53,6 +53,7 @@
<Compile Include="PerspexObjectExtensions.cs" />
<Compile Include="PerspexPropertyRegistry.cs" />
<Compile Include="PerspexProperty`1.cs" />
<Compile Include="Platform\IAssetLoader.cs" />
<Compile Include="Platform\IPclPlatformWrapper.cs" />
<Compile Include="BindingPriority.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="HotkeyManager.cs" />
<Compile Include="Platform\ITopLevelRenderer.cs" />
<Compile Include="Platform\IWindowingPlatform.cs" />
<Compile Include="Platform\PlatformManager.cs" />
<Compile Include="SelectionMode.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.Collections.Generic;
using System.Linq;
using System.Reactive.Disposables;
using System.Text;
using System.Threading.Tasks;
using Perspex.Input;
@ -17,6 +18,9 @@ namespace Perspex.Controls.Platform
static IPlatformSettings GetSettings()
=> PerspexLocator.Current.GetService<IPlatformSettings>();
static bool s_designerMode;
private static double _designerScalingFactor = 1;
public static IRenderTarget CreateRenderTarget(ITopLevelImpl window)
{
return
@ -24,6 +28,19 @@ namespace Perspex.Controls.Platform
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
{
@ -45,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));
@ -62,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)
{
@ -165,12 +182,14 @@ namespace Perspex.Controls.Platform
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()
{
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.Text;
using System.Threading.Tasks;
using System.Windows.Media;
using JetBrains.Annotations;
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;
Background = Settings.Background;
}
public IntPtr 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)
{
Error = error;
ErrorDetails = details;
}
double _currentScalingFactor = 1;
private string _color;
private string _background;
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]

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

@ -18,17 +18,17 @@ namespace Perspex.Designer.AppHost
class PerspexAppHost
{
private string _appDir;
private CommChannel _comm;
private readonly CommChannel _comm;
private string _lastXaml;
private string _currentXaml;
private Func<Stream, object> _xamlReader;
private bool _initSuccess;
private HostedAppModel _appModel = new HostedAppModel();
private HostedAppModel _appModel;
private Control _window;
public PerspexAppHost(CommChannel channel)
{
_comm = channel;
_appModel = new HostedAppModel(this);
}
public void Start()
@ -92,8 +92,6 @@ namespace Perspex.Designer.AppHost
PerspexDesignerMetadata BuildMetadata(List<Assembly> asms, Type xmlNsAttr)
{
var rv = new PerspexDesignerMetadata()
{
@ -200,34 +198,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<string, object>();
Api = new DesignerApi(dic) {OnResize = OnResize, OnWindowCreated = OnWindowCreated};
LookupStaticMethod("Perspex.Designer.Designer", "Init").Invoke(null, new object[] {dic});
_window = new Control
{
@ -242,15 +216,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 +247,11 @@ namespace Perspex.Designer.AppHost
return true;
}
private void OnResize()
{
}
void XamlUpdater()
{
if (!_initSuccess)
@ -282,27 +265,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 +276,8 @@ namespace Perspex.Designer.AppHost
_appModel.SetError("XAML load error", e.ToString());
}
}
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";
Controls.Add(_windowHost);
_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"};
@ -43,6 +55,12 @@ namespace Perspex.Designer.AppHost
base.WndProc(ref m);
}
protected override void OnPaint(PaintEventArgs e)
{
using (var b = new SolidBrush(BackColor))
e.Graphics.FillRectangle(b, e.ClipRectangle);
}
void FixPosition()
{
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
{
internal class CommChannel : IDisposable
class CommChannel : IDisposable
{
private readonly BinaryReader _input;
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: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}">
<DockPanel>
<Border x:Name="ErrorPanel" DockPanel.Dock="Bottom" BorderBrush="Red" BorderThickness="3" Padding="3">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Error}" FontSize="16"/>
<TextBlock x:Name="DetailsBlock" FontSize="16">
<StackPanel Orientation="Horizontal" DockPanel.Dock="Bottom">
<ComboBox ItemsSource="{Binding AvailableScalingFactors}" SelectedItem="{Binding CurrentScalingFactor, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<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>
</TextBlock>
</StackPanel>
</Border>
</TextBlock>
</StackPanel>
</Border>
</StackPanel>
<WindowsFormsHost x:Name="WindowHostControl"/>
</DockPanel>
</UserControl>

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

@ -1,18 +1,21 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Perspex.Designer.AppHost;
using TextBox = System.Windows.Controls.TextBox;
using UserControl = System.Windows.Controls.UserControl;
namespace Perspex.Designer.InProcDesigner
{
@ -80,5 +83,16 @@ namespace Perspex.Designer.InProcDesigner
};
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" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\Perspex.Application\Designer\DesignerApi.cs">
<Link>AppHost\DesignerApi.cs</Link>
</Compile>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
</Compile>
@ -94,6 +97,7 @@
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Settings.cs" />
<Compile Include="WinApi.cs" />
</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
{
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<IPopupImpl>().ToTransient<PopupImpl>()
.Bind<IClipboard>().ToSingleton<ClipboardImpl>()
.Bind<IStandardCursorFactory>().ToConstant(CursorFactory.Instance)
.Bind<IKeyboardDevice>().ToConstant(WindowsKeyboardDevice.Instance)
.Bind<IMouseDevice>().ToConstant(WindowsMouseDevice.Instance)
.Bind<IPlatformSettings>().ToConstant(s_instance)
.Bind<IPlatformThreadingInterface>().ToConstant(s_instance)
.Bind<ISystemDialogImpl>().ToSingleton<SystemDialogImpl>();
.Bind<ISystemDialogImpl>().ToSingleton<SystemDialogImpl>()
.Bind<IWindowingPlatform>().ToConstant(s_instance);
SharedPlatform.Register();
_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()
{
UnmanagedMethods.MSG msg;
@ -169,5 +157,20 @@ namespace Perspex.Win32
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<IPlatformSettings>().ToSingleton<PlatformSettings>()
.Bind<IPlatformThreadingInterface>().ToConstant(PlatformThreadingInterface.Instance)
.Bind<IWindowImpl>().ToConstant(controller.PerspexView);
.Bind<IWindowingPlatform>().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 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="ListBoxTests_Single.cs" />
<Compile Include="Primitives\SelectingItemsControlTests_Multiple.cs" />
<Compile Include="WindowingPlatformMock.cs" />
<Compile Include="TreeViewTests.cs" />
<Compile Include="Mixins\SelectableMixinTests.cs" />
<Compile Include="StackPanelTests.cs" />

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

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

4
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<IWindowImpl>();
var styler = new Mock<Styler>();
PerspexLocator.CurrentMutable
.Bind<IWindowImpl>().ToConstant(windowImpl.Object)
.Bind<IWindowingPlatform>().ToConstant(new WindowingPlatformMock())
.Bind<IStyler>().ToConstant(styler.Object);
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.Primitives;
using Perspex.Controls.Templates;
using Perspex.Controls.UnitTests;
using Perspex.Controls.UnitTests.Primitives;
using Perspex.Diagnostics;
using Perspex.Input;
using Perspex.Platform;
@ -149,7 +151,7 @@ namespace Perspex.Layout.UnitTests
.Bind<IPlatformRenderInterface>().ToConstant(renderInterface)
.Bind<IRenderQueueManager>().ToConstant(renderManager)
.Bind<IStyler>().ToConstant(new Styler())
.Bind<IWindowImpl>().ToConstant(windowImpl.Object);
.Bind<IWindowingPlatform>().ToConstant(new WindowingPlatformMock(() => windowImpl.Object));
var theme = new DefaultTheme();
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>
<Name>Perspex.Themes.Default</Name>
</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>
<None Include="app.config" />

Loading…
Cancel
Save