400 строки
11 KiB
C#
400 строки
11 KiB
C#
//
|
|
// WindowFrameBackend.cs
|
|
//
|
|
// Author:
|
|
// Carlos Alberto Cortez <calberto.cortez@gmail.com>
|
|
//
|
|
// Copyright (c) 2011 Carlos Alberto Cortez
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
// THE SOFTWARE.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Windows;
|
|
|
|
using Xwt.Backends;
|
|
|
|
|
|
namespace Xwt.WPFBackend
|
|
{
|
|
public class WindowFrameBackend : IWindowFrameBackend
|
|
{
|
|
System.Windows.Window window;
|
|
IWindowFrameEventSink eventSink;
|
|
WindowFrame frontend;
|
|
bool resizable = true;
|
|
|
|
public WindowFrameBackend ()
|
|
{
|
|
}
|
|
|
|
void IBackend.InitializeBackend (object frontend, ApplicationContext context)
|
|
{
|
|
this.frontend = (WindowFrame) frontend;
|
|
Context = context;
|
|
}
|
|
|
|
void IWindowFrameBackend.Initialize (IWindowFrameEventSink eventSink)
|
|
{
|
|
this.eventSink = eventSink;
|
|
Initialize ();
|
|
}
|
|
|
|
public ApplicationContext Context { get; private set; }
|
|
|
|
public virtual void Initialize ()
|
|
{
|
|
}
|
|
|
|
public virtual void Dispose ()
|
|
{
|
|
Window.Close ();
|
|
}
|
|
|
|
public bool Close ()
|
|
{
|
|
closePerformed = true;
|
|
Window.Close ();
|
|
return closePerformed;
|
|
}
|
|
|
|
public System.Windows.Window Window {
|
|
get { return window; }
|
|
set { window = value; }
|
|
}
|
|
|
|
public virtual bool HasMenu {
|
|
get { return false; }
|
|
}
|
|
|
|
protected WindowFrame Frontend {
|
|
get { return frontend; }
|
|
}
|
|
|
|
public IWindowFrameEventSink EventSink
|
|
{
|
|
get { return eventSink; }
|
|
}
|
|
|
|
bool IWindowFrameBackend.Decorated {
|
|
get { return window.WindowStyle != WindowStyle.None; }
|
|
set {
|
|
window.WindowStyle = value ? WindowStyle.SingleBorderWindow : WindowStyle.None;
|
|
UpdateResizeMode ();
|
|
}
|
|
}
|
|
|
|
bool IWindowFrameBackend.ShowInTaskbar {
|
|
get { return window.ShowInTaskbar; }
|
|
set { window.ShowInTaskbar = value; }
|
|
}
|
|
|
|
void IWindowFrameBackend.SetTransientFor (IWindowFrameBackend window)
|
|
{
|
|
this.Window.Owner = ((WindowFrameBackend) window).Window;
|
|
}
|
|
|
|
bool IWindowFrameBackend.Resizable {
|
|
get {
|
|
return resizable;
|
|
}
|
|
set {
|
|
if (value != resizable) {
|
|
resizable = value;
|
|
UpdateResizeMode ();
|
|
var bounds = Bounds;
|
|
window.ResizeMode = value ? ResizeMode.CanResize : ResizeMode.NoResize;
|
|
if (window.IsLoaded && bounds != Bounds) {
|
|
// The size of the border of resizable windows is different from fixed windows.
|
|
// If we change the resize mode, the border size will change, and the client
|
|
// area will then change. Here, we restore the client area to the size it
|
|
// had before the mode change.
|
|
Bounds = bounds;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void UpdateResizeMode ()
|
|
{
|
|
var m = resizable && window.WindowStyle == WindowStyle.SingleBorderWindow ? ResizeMode.CanResize : ResizeMode.NoResize;
|
|
if (m != window.ResizeMode) {
|
|
window.ResizeMode = m;
|
|
OnResizeModeChanged ();
|
|
}
|
|
}
|
|
|
|
protected virtual void OnResizeModeChanged ()
|
|
{
|
|
}
|
|
|
|
public void SetIcon (ImageDescription imageBackend)
|
|
{
|
|
window.Icon = imageBackend.ToImageSource ();
|
|
}
|
|
|
|
string IWindowFrameBackend.Title {
|
|
get { return window.Title; }
|
|
set { window.Title = value; }
|
|
}
|
|
|
|
bool IWindowFrameBackend.Visible
|
|
{
|
|
get { return window.Visibility == Visibility.Visible; }
|
|
set {
|
|
if (value)
|
|
window.Show ();
|
|
else
|
|
window.Hide ();
|
|
}
|
|
}
|
|
|
|
public double Opacity
|
|
{
|
|
get { return window.Opacity; }
|
|
set { window.Opacity = value; }
|
|
}
|
|
|
|
void IWindowFrameBackend.Present ()
|
|
{
|
|
window.Activate ();
|
|
}
|
|
|
|
|
|
bool IWindowFrameBackend.FullScreen {
|
|
get {
|
|
return false;
|
|
}
|
|
set {
|
|
}
|
|
}
|
|
|
|
object IWindowFrameBackend.Screen {
|
|
get {
|
|
var sb = Bounds;
|
|
return System.Windows.Forms.Screen.FromRectangle (new System.Drawing.Rectangle ((int)sb.X, (int)sb.Y, (int)sb.Width, (int)sb.Height));
|
|
}
|
|
}
|
|
|
|
public void Move (double x, double y)
|
|
{
|
|
var value = ToNonClientRect (new Rectangle (x, y, 1, 1));
|
|
window.Top = value.Top;
|
|
window.Left = value.Left;
|
|
Context.InvokeUserCode (delegate
|
|
{
|
|
eventSink.OnBoundsChanged (Bounds);
|
|
});
|
|
}
|
|
|
|
public void SetSize (double width, double height)
|
|
{
|
|
var r = Bounds;
|
|
r.Width = width;
|
|
r.Height = height;
|
|
Bounds = r;
|
|
}
|
|
|
|
public virtual Rectangle Bounds {
|
|
get {
|
|
double width = Double.IsNaN (window.Width) ? window.ActualWidth : window.Width;
|
|
double height = Double.IsNaN (window.Height) ? window.ActualHeight : window.Height;
|
|
return ToClientRect (new Rectangle (window.Left, window.Top, width, height));
|
|
}
|
|
set {
|
|
value = ToNonClientRect (value);
|
|
window.Top = value.Top;
|
|
window.Left = value.Left;
|
|
window.Width = value.Width;
|
|
window.Height = value.Height;
|
|
Context.InvokeUserCode (delegate {
|
|
eventSink.OnBoundsChanged (Bounds);
|
|
});
|
|
}
|
|
}
|
|
|
|
public virtual void EnableEvent (object eventId)
|
|
{
|
|
if (eventId is WindowFrameEvent) {
|
|
switch ((WindowFrameEvent)eventId) {
|
|
case WindowFrameEvent.BoundsChanged:
|
|
window.LocationChanged += BoundsChangedHandler;
|
|
window.SizeChanged += BoundsChangedHandler;
|
|
break;
|
|
case WindowFrameEvent.Shown:
|
|
window.IsVisibleChanged += ShownHandler;
|
|
break;
|
|
case WindowFrameEvent.Hidden:
|
|
window.IsVisibleChanged += HiddenHandler;
|
|
break;
|
|
case WindowFrameEvent.CloseRequested:
|
|
window.Closing += ClosingHandler;
|
|
break;
|
|
case WindowFrameEvent.Closed:
|
|
window.Closed += ClosedHandler;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
public virtual void DisableEvent (object eventId)
|
|
{
|
|
if (eventId is WindowFrameEvent) {
|
|
switch ((WindowFrameEvent)eventId) {
|
|
case WindowFrameEvent.BoundsChanged:
|
|
window.LocationChanged -= BoundsChangedHandler;
|
|
window.SizeChanged -= BoundsChangedHandler;
|
|
break;
|
|
case WindowFrameEvent.Shown:
|
|
window.IsVisibleChanged -= ShownHandler;
|
|
break;
|
|
case WindowFrameEvent.Hidden:
|
|
window.IsVisibleChanged -= HiddenHandler;
|
|
break;
|
|
case WindowFrameEvent.CloseRequested:
|
|
window.Closing -= ClosingHandler;
|
|
break;
|
|
case WindowFrameEvent.Closed:
|
|
window.Closing -= ClosedHandler;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ClosedHandler (object sender, EventArgs e)
|
|
{
|
|
if (!InhibitCloseRequested)
|
|
Context.InvokeUserCode (eventSink.OnClosed);
|
|
}
|
|
|
|
void BoundsChangedHandler (object o, EventArgs args)
|
|
{
|
|
Context.InvokeUserCode (delegate () {
|
|
eventSink.OnBoundsChanged (Bounds);
|
|
});
|
|
}
|
|
|
|
private void ShownHandler (object sender, DependencyPropertyChangedEventArgs e)
|
|
{
|
|
// delay shown event until window is loaded
|
|
if (!window.IsLoaded) {
|
|
window.Loaded += (sender2, e2) => ShownHandler (sender, e);
|
|
return;
|
|
}
|
|
if((bool)e.NewValue)
|
|
{
|
|
Context.InvokeUserCode (delegate ()
|
|
{
|
|
eventSink.OnShown ();
|
|
});
|
|
}
|
|
}
|
|
|
|
private void HiddenHandler (object sender, DependencyPropertyChangedEventArgs e)
|
|
{
|
|
if((bool)e.NewValue == false)
|
|
{
|
|
Context.InvokeUserCode (delegate ()
|
|
{
|
|
eventSink.OnHidden ();
|
|
});
|
|
}
|
|
}
|
|
|
|
protected bool InhibitCloseRequested { get; set; }
|
|
|
|
bool closePerformed;
|
|
|
|
private void ClosingHandler (object sender, System.ComponentModel.CancelEventArgs e)
|
|
{
|
|
if (InhibitCloseRequested)
|
|
return;
|
|
Context.InvokeUserCode (delegate ()
|
|
{
|
|
e.Cancel = !eventSink.OnCloseRequested ();
|
|
closePerformed = !e.Cancel;
|
|
});
|
|
}
|
|
|
|
Size GetBorderSize ()
|
|
{
|
|
if (window.ResizeMode == ResizeMode.CanResize)
|
|
return new Size (SystemParameters.ResizeFrameVerticalBorderWidth, SystemParameters.ResizeFrameHorizontalBorderHeight);
|
|
else
|
|
return new Size (SystemParameters.FixedFrameVerticalBorderWidth, SystemParameters.FixedFrameHorizontalBorderHeight);
|
|
}
|
|
|
|
protected Rectangle ToNonClientRect (Rectangle rect)
|
|
{
|
|
// WARNING: SystemParameters.ResizeFrameHorizontalBorderHeight is known to return invalid values in some cases, due to
|
|
// a workaround in the Windows API to support legacy applications running on Aero.
|
|
// We can't rely then on ToNonClientRect and ToClientRect to return 100% correct values, so they are not used for calculating
|
|
// the required client area. However, the result of those methods is good enough for calculating the position of the window.
|
|
|
|
var size = rect.Size;
|
|
var loc = rect.Location;
|
|
|
|
var border = GetBorderSize ();
|
|
size.Height += border.Height * 2;
|
|
size.Width += border.Width * 2;
|
|
loc.X -= border.Width;
|
|
loc.Y -= border.Height;
|
|
|
|
if (((IWindowFrameBackend)this).Decorated) {
|
|
size.Height += SystemParameters.WindowCaptionHeight;
|
|
loc.Y -= SystemParameters.WindowCaptionHeight;
|
|
}
|
|
if (HasMenu) {
|
|
size.Height += SystemParameters.MenuBarHeight;
|
|
loc.Y -= SystemParameters.MenuBarHeight;
|
|
}
|
|
|
|
return new Rectangle (loc, size);
|
|
}
|
|
|
|
protected Rectangle ToClientRect (Rectangle rect)
|
|
{
|
|
var size = rect.Size;
|
|
var loc = rect.Location;
|
|
|
|
var border = GetBorderSize ();
|
|
size.Height -= border.Height * 2;
|
|
size.Width -= border.Width * 2;
|
|
loc.X += border.Width;
|
|
loc.Y += border.Height;
|
|
|
|
if (((IWindowFrameBackend)this).Decorated) {
|
|
size.Height -= SystemParameters.WindowCaptionHeight;
|
|
loc.Y += SystemParameters.WindowCaptionHeight;
|
|
}
|
|
if (HasMenu) {
|
|
size.Height -= SystemParameters.MenuBarHeight;
|
|
loc.Y += SystemParameters.MenuBarHeight;
|
|
}
|
|
|
|
size.Width = Math.Max (0, size.Width);
|
|
size.Height = Math.Max (0, size.Height);
|
|
|
|
return new Rectangle (loc, size);
|
|
}
|
|
}
|
|
}
|