Browse Source

Allow Windows to be shown as dialogs.

pull/39/head
Steven Kirk 12 years ago
parent
commit
af3697b907
  1. 11
      Gtk/Perspex.Gtk/WindowImpl.cs
  2. 2
      Perspex.Controls/Platform/ITopLevelImpl.cs
  3. 5
      Perspex.Controls/Platform/IWindowImpl.cs
  4. 17
      Perspex.Controls/TopLevel.cs
  5. 41
      Perspex.Controls/Window.cs
  6. 39
      TestApplication/Program.cs
  7. 9
      Windows/Perspex.Win32/Interop/UnmanagedMethods.cs
  8. 51
      Windows/Perspex.Win32/WindowImpl.cs

11
Gtk/Perspex.Gtk/WindowImpl.cs

@ -7,6 +7,7 @@
namespace Perspex.Gtk namespace Perspex.Gtk
{ {
using System; using System;
using System.Threading.Tasks;
using Perspex.Controls; using Perspex.Controls;
using Perspex.Input.Raw; using Perspex.Input.Raw;
using Perspex.Platform; using Perspex.Platform;
@ -79,6 +80,16 @@ namespace Perspex.Gtk
this.Title = title; this.Title = title;
} }
public IDisposable ShowDialog()
{
throw new NotImplementedException();
}
void ITopLevelImpl.Activate()
{
this.Activate();
}
protected override bool OnButtonPressEvent(Gdk.EventButton evnt) protected override bool OnButtonPressEvent(Gdk.EventButton evnt)
{ {
var e = new RawMouseEventArgs( var e = new RawMouseEventArgs(

2
Perspex.Controls/Platform/ITopLevelImpl.cs

@ -29,6 +29,8 @@ namespace Perspex.Platform
Action<Size> Resized { get; set; } Action<Size> Resized { get; set; }
void Activate();
void Invalidate(Rect rect); void Invalidate(Rect rect);
void SetOwner(TopLevel owner); void SetOwner(TopLevel owner);

5
Perspex.Controls/Platform/IWindowImpl.cs

@ -6,7 +6,8 @@
namespace Perspex.Platform namespace Perspex.Platform
{ {
using Perspex.Controls; using System;
using System.Threading.Tasks;
public interface IWindowImpl : ITopLevelImpl public interface IWindowImpl : ITopLevelImpl
{ {
@ -14,6 +15,8 @@ namespace Perspex.Platform
void Show(); void Show();
IDisposable ShowDialog();
void Hide(); void Hide();
} }
} }

17
Perspex.Controls/TopLevel.cs

@ -24,6 +24,9 @@ namespace Perspex.Controls
public static readonly PerspexProperty<Size> ClientSizeProperty = public static readonly PerspexProperty<Size> ClientSizeProperty =
PerspexProperty.Register<TopLevel, Size>("ClientSize"); PerspexProperty.Register<TopLevel, Size>("ClientSize");
public static readonly PerspexProperty<bool> IsActiveProperty =
PerspexProperty.Register<Window, bool>("IsActive");
private Dispatcher dispatcher; private Dispatcher dispatcher;
private IRenderManager renderManager; private IRenderManager renderManager;
@ -113,6 +116,12 @@ namespace Perspex.Controls
set { this.SetValue(ClientSizeProperty, value); } set { this.SetValue(ClientSizeProperty, value); }
} }
public bool IsActive
{
get { return this.GetValue(IsActiveProperty); }
private set { this.SetValue(IsActiveProperty, value); }
}
public ILayoutManager LayoutManager public ILayoutManager LayoutManager
{ {
get; get;
@ -140,6 +149,11 @@ namespace Perspex.Controls
return this.PlatformImpl.PointToScreen(p); return this.PlatformImpl.PointToScreen(p);
} }
public void Activate()
{
this.PlatformImpl.Activate();
}
protected IDisposable BeginAutoSizing() protected IDisposable BeginAutoSizing()
{ {
this.autoSizing = true; this.autoSizing = true;
@ -174,6 +188,7 @@ namespace Perspex.Controls
} }
FocusManager.Instance.SetFocusScope(this); FocusManager.Instance.SetFocusScope(this);
this.IsActive = true;
} }
private void HandleClosed() private void HandleClosed()
@ -186,6 +201,8 @@ namespace Perspex.Controls
private void HandleDeactivated() private void HandleDeactivated()
{ {
this.IsActive = false;
if (this.Deactivated != null) if (this.Deactivated != null)
{ {
this.Deactivated(this, EventArgs.Empty); this.Deactivated(this, EventArgs.Empty);

41
Perspex.Controls/Window.cs

@ -7,6 +7,8 @@
namespace Perspex.Controls namespace Perspex.Controls
{ {
using System; using System;
using System.Reactive.Linq;
using System.Threading.Tasks;
using Perspex.Media; using Perspex.Media;
using Perspex.Platform; using Perspex.Platform;
using Perspex.Styling; using Perspex.Styling;
@ -17,6 +19,8 @@ namespace Perspex.Controls
public static readonly PerspexProperty<string> TitleProperty = public static readonly PerspexProperty<string> TitleProperty =
PerspexProperty.Register<Window, string>("Title", "Window"); PerspexProperty.Register<Window, string>("Title", "Window");
private object dialogResult;
static Window() static Window()
{ {
BackgroundProperty.OverrideDefaultValue(typeof(Window), Brushes.White); BackgroundProperty.OverrideDefaultValue(typeof(Window), Brushes.White);
@ -43,6 +47,17 @@ namespace Perspex.Controls
get { return typeof(Window); } get { return typeof(Window); }
} }
public void Close()
{
this.PlatformImpl.Dispose();
}
public void Close(object dialogResult)
{
this.dialogResult = dialogResult;
this.Close();
}
public void Hide() public void Hide()
{ {
using (this.BeginAutoSizing()) using (this.BeginAutoSizing())
@ -60,5 +75,31 @@ namespace Perspex.Controls
this.PlatformImpl.Show(); this.PlatformImpl.Show();
} }
} }
public Task ShowDialog()
{
return this.ShowDialog<object>();
}
public Task<TResult> ShowDialog<TResult>()
{
this.ExecuteLayoutPass();
using (this.BeginAutoSizing())
{
var modal = this.PlatformImpl.ShowDialog();
var result = new TaskCompletionSource<TResult>();
Observable.FromEventPattern(this, nameof(Closed))
.Take(1)
.Subscribe(_ =>
{
modal.Dispose();
result.SetResult((TResult)this.dialogResult);
});
return result.Task;
}
}
} }
} }

39
TestApplication/Program.cs

@ -11,12 +11,11 @@ using Perspex.Layout;
using Perspex.Media; using Perspex.Media;
using Perspex.Media.Imaging; using Perspex.Media.Imaging;
using Perspex.Rendering; using Perspex.Rendering;
using Perspex.Styling;
using Perspex.Threading; using Perspex.Threading;
#if PERSPEX_GTK #if PERSPEX_GTK
using Perspex.Gtk; using Perspex.Gtk;
#else #else
using Perspex.Win32; using ReactiveUI;
#endif #endif
using Splat; using Splat;
@ -189,7 +188,10 @@ namespace TestApplication
private static TabItem ButtonsTab() private static TabItem ButtonsTab()
{ {
return new TabItem var showDialog = ReactiveCommand.Create();
Button showDialogButton;
var result = new TabItem
{ {
Header = "Buttons", Header = "Buttons",
Content = new StackPanel Content = new StackPanel
@ -201,10 +203,11 @@ namespace TestApplication
MinWidth = 120, MinWidth = 120,
Children = new Controls Children = new Controls
{ {
new Button (showDialogButton = new Button
{ {
Content = "Button", Content = "Button",
}, Command = showDialog,
}),
new Button new Button
{ {
Content = "Button", Content = "Button",
@ -246,6 +249,31 @@ namespace TestApplication
} }
}, },
}; };
showDialog.Subscribe(async _ =>
{
var close = ReactiveCommand.Create();
var dialog = new Window
{
Content = new StackPanel
{
Width = 200,
Height = 200,
Children = new Controls
{
new Button { Content = "Yes", Command = close, CommandParameter = "Yes" },
new Button { Content = "No", Command = close, CommandParameter = "No" },
}
}
};
close.Subscribe(x => dialog.Close(x));
showDialogButton.Content = await dialog.ShowDialog<string>();
});
return result;
} }
private static TabItem TextTab() private static TabItem TextTab()
@ -582,6 +610,5 @@ namespace TestApplication
return result; return result;
} }
} }
} }

9
Windows/Perspex.Win32/Interop/UnmanagedMethods.cs

@ -516,6 +516,9 @@ namespace Perspex.Win32.Interop
[DllImport("user32.dll", SetLastError = true)] [DllImport("user32.dll", SetLastError = true)]
public static extern bool DestroyWindow(IntPtr hwnd); public static extern bool DestroyWindow(IntPtr hwnd);
[DllImport("user32.dll")]
public static extern bool EnableWindow(IntPtr hWnd, bool bEnable);
[DllImport("user32.dll")] [DllImport("user32.dll")]
public static extern bool EndPaint(IntPtr hWnd, ref PAINTSTRUCT lpPaint); public static extern bool EndPaint(IntPtr hWnd, ref PAINTSTRUCT lpPaint);
@ -558,6 +561,9 @@ namespace Perspex.Win32.Interop
[DllImport("user32.dll")] [DllImport("user32.dll")]
public static extern bool InvalidateRect(IntPtr hWnd, ref RECT lpRect, bool bErase); public static extern bool InvalidateRect(IntPtr hWnd, ref RECT lpRect, bool bErase);
[DllImport("user32.dll")]
public static extern bool IsWindowEnabled(IntPtr hWnd);
[DllImport("user32.dll")] [DllImport("user32.dll")]
public static extern bool KillTimer(IntPtr hWnd, IntPtr uIDEvent); public static extern bool KillTimer(IntPtr hWnd, IntPtr uIDEvent);
@ -579,6 +585,9 @@ namespace Perspex.Win32.Interop
[DllImport("user32.dll")] [DllImport("user32.dll")]
public static extern bool ScreenToClient(IntPtr hWnd, ref POINT lpPoint); public static extern bool ScreenToClient(IntPtr hWnd, ref POINT lpPoint);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SetActiveWindow(IntPtr hWnd);
[DllImport("user32.dll")] [DllImport("user32.dll")]
public static extern IntPtr SetCapture(IntPtr hWnd); public static extern IntPtr SetCapture(IntPtr hWnd);

51
Windows/Perspex.Win32/WindowImpl.cs

@ -7,9 +7,14 @@
namespace Perspex.Win32 namespace Perspex.Win32
{ {
using System; using System;
using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Perspex.Controls; using Perspex.Controls;
using Perspex.Input.Raw; using Perspex.Input.Raw;
using Perspex.Platform; using Perspex.Platform;
@ -18,6 +23,8 @@ namespace Perspex.Win32
public class WindowImpl : IWindowImpl public class WindowImpl : IWindowImpl
{ {
private static List<WindowImpl> instances = new List<WindowImpl>();
private UnmanagedMethods.WndProc wndProcDelegate; private UnmanagedMethods.WndProc wndProcDelegate;
private string className; private string className;
@ -31,6 +38,7 @@ namespace Perspex.Win32
public WindowImpl() public WindowImpl()
{ {
this.CreateWindow(); this.CreateWindow();
instances.Add(this);
} }
public Action Activated { get; set; } public Action Activated { get; set; }
@ -83,6 +91,17 @@ namespace Perspex.Win32
private set; private set;
} }
public bool IsEnabled
{
get { return UnmanagedMethods.IsWindowEnabled(this.hwnd); }
set { UnmanagedMethods.EnableWindow(this.hwnd, value); }
}
public void Activate()
{
UnmanagedMethods.SetActiveWindow(this.hwnd);
}
public IPopupImpl CreatePopup() public IPopupImpl CreatePopup()
{ {
return new PopupImpl(); return new PopupImpl();
@ -90,6 +109,7 @@ namespace Perspex.Win32
public void Dispose() public void Dispose()
{ {
instances.Remove(this);
UnmanagedMethods.DestroyWindow(this.hwnd); UnmanagedMethods.DestroyWindow(this.hwnd);
} }
@ -133,6 +153,37 @@ namespace Perspex.Win32
UnmanagedMethods.ShowWindow(this.hwnd, UnmanagedMethods.ShowWindowCommand.Normal); UnmanagedMethods.ShowWindow(this.hwnd, UnmanagedMethods.ShowWindowCommand.Normal);
} }
public virtual IDisposable ShowDialog()
{
var disabled = instances.Where(x => x != this && x.IsEnabled).ToList();
TopLevel activated = null;
foreach (var window in disabled)
{
if (window.owner.IsActive)
{
activated = window.owner;
}
window.IsEnabled = false;
}
this.Show();
return Disposable.Create(() =>
{
foreach (var window in disabled)
{
window.IsEnabled = true;
}
if (activated != null)
{
activated.Activate();
}
});
}
protected virtual IntPtr CreateWindowOverride(ushort atom) protected virtual IntPtr CreateWindowOverride(ushort atom)
{ {
return UnmanagedMethods.CreateWindowEx( return UnmanagedMethods.CreateWindowEx(

Loading…
Cancel
Save