xwt/Xwt.WPF/Xwt.WPFBackend/WidgetBackend.cs

1016 строки
30 KiB
C#
Исходник Обычный вид История

//
// WidgetBackend.cs
//
// Authors:
// Carlos Alberto Cortez <calberto.cortez@gmail.com>
// Eric Maupin <ermau@xamarin.com>
//
// Copyright (c) 2011 Carlos Alberto Cortez
// Copyright (c) 2012 Xamarin, Inc.
//
// 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.Specialized;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
2012-04-24 01:56:34 +04:00
using System.Windows.Documents;
using System.Windows.Input;
2012-03-09 23:40:40 +04:00
using System.Windows.Media;
using SWM = System.Windows.Media;
using SWC = System.Windows.Controls; // When we need to resolve ambigituies.
using SW = System.Windows; // When we need to resolve ambigituies.
using Xwt.Backends;
2012-11-23 16:00:42 +04:00
2012-03-09 23:40:40 +04:00
using Color = Xwt.Drawing.Color;
namespace Xwt.WPFBackend
{
public abstract class WidgetBackend
: Backend, IWidgetBackend, IWpfWidgetBackend
{
IWidgetEventSink eventSink;
WidgetEvent enabledEvents;
DragDropEffects currentDragEffect;
FrameworkElement widget;
class DragDropData
{
// Source
public bool AutodetectDrag;
public Rect DragRect = Rect.Empty;
// Target
public TransferDataType [] TargetTypes = new TransferDataType [0];
}
DragDropData dragDropInfo;
const WidgetEvent dragDropEvents = WidgetEvent.DragDropCheck | WidgetEvent.DragDrop | WidgetEvent.DragOver | WidgetEvent.DragOverCheck;
// Set to true when measuring a natural size for this widget
bool gettingNaturalSize;
// Set to true when calculating the default preferred size of the widget
bool calculatingPreferredSize;
void IWidgetBackend.Initialize (IWidgetEventSink eventSink)
{
this.eventSink = eventSink;
Initialize ();
}
protected virtual void Initialize ()
{
}
~WidgetBackend ()
{
Dispose (false);
}
public void Dispose ()
{
GC.SuppressFinalize (this);
Dispose (true);
}
protected virtual void Dispose (bool disposing)
{
}
public IWidgetEventSink EventSink {
get { return eventSink; }
}
public object NativeWidget {
get { return Widget; }
}
public new Widget Frontend {
get { return (Widget) base.Frontend; }
}
public FrameworkElement Widget {
get { return widget; }
set
{
widget = value;
if (widget is IWpfWidget)
((IWpfWidget)widget).Backend = this;
widget.InvalidateMeasure ();
}
}
Color? customBackgroundColor;
public virtual Color BackgroundColor {
get {
if (customBackgroundColor.HasValue)
return customBackgroundColor.Value;
return DataConverter.ToXwtColor (GetWidgetColor ());
}
set {
customBackgroundColor = value;
SetWidgetColor (value);
}
}
public bool BackgroundColorSet
{
get { return customBackgroundColor.HasValue; }
}
SWM.Color GetWidgetColor ()
{
if (Widget is Control) {
var control = (Control)Widget;
if (control.Background != null)
return ((SWM.SolidColorBrush)control.Background).Color;
} else if (Widget is SWC.Panel) {
var panel = (SWC.Panel)Widget;
if (panel.Background != null)
return ((SWM.SolidColorBrush)panel.Background).Color;
}
return SystemColors.ControlColor;
}
protected virtual void SetWidgetColor (Color value)
{
if ((Widget is Control))
((Control)Widget).Background = ResPool.GetSolidBrush (value);
if ((Widget is System.Windows.Controls.Panel))
((SWC.Panel)Widget).Background = ResPool.GetSolidBrush (value);
}
public bool UsingCustomBackgroundColor {
get { return customBackgroundColor.HasValue; }
}
public virtual object Font {
get { return GetWidgetFont (); }
set {
SetWidgetFont ((FontData)value);
}
}
2013-07-10 23:05:59 +04:00
public double Opacity {
get { return Widget.Opacity; }
set { Widget.Opacity = value; }
}
FontData GetWidgetFont ()
{
if (!(Widget is Control)) {
2012-12-07 16:12:39 +04:00
double size = WpfFontBackendHandler.GetPointsFromDeviceUnits (SystemFonts.MessageFontSize);
2013-03-25 22:38:48 +04:00
return new FontData (SystemFonts.MessageFontFamily, size) {
Style = SystemFonts.MessageFontStyle,
Weight = SystemFonts.MessageFontWeight
};
}
return FontData.FromControl ((Control)Widget);
}
void SetWidgetFont (FontData font)
{
if (!(Widget is Control))
return;
var control = (Control)Widget;
control.FontFamily = font.Family;
control.FontSize = font.GetDeviceIndependentPixelSize (control);
control.FontStyle = font.Style;
control.FontWeight = font.Weight;
control.FontStretch = font.Stretch;
}
public bool CanGetFocus {
get { return Widget.Focusable; }
set { Widget.Focusable = value; }
}
public bool HasFocus {
get { return Widget.IsFocused; }
}
public void SetFocus ()
{
if (Widget.IsLoaded)
Widget.Focus ();
else
Widget.Loaded += DeferredFocus;
}
void DeferredFocus (object sender, RoutedEventArgs e)
{
Widget.Loaded -= DeferredFocus;
Widget.Focus ();
}
public virtual bool Sensitive {
get { return Widget.IsEnabled; }
set { Widget.IsEnabled = value; }
}
public Size Size {
2013-05-09 19:19:36 +04:00
get { return new Size (Widget.RenderSize.Width, Widget.RenderSize.Height); }
}
public virtual bool Visible {
get { return Widget.Visibility == Visibility.Visible; }
2012-04-24 01:57:03 +04:00
set { Widget.Visibility = value ? Visibility.Visible : Visibility.Collapsed; }
}
public string TooltipText {
get { return Widget.ToolTip.ToString (); }
set { Widget.ToolTip = value; }
}
public static FrameworkElement GetFrameworkElement (IWidgetBackend backend)
{
return backend == null ? null : (FrameworkElement)backend.NativeWidget;
}
public Point ConvertToScreenCoordinates (Point widgetCoordinates)
{
2012-03-24 02:20:00 +04:00
var p = Widget.PointToScreen (new System.Windows.Point (
widgetCoordinates.X, widgetCoordinates.Y));
return new Point (p.X, p.Y);
}
SW.Size lastNaturalSize;
2013-05-31 11:44:45 +04:00
void GetWidgetDesiredSize (double availableWidth, double availableHeight, out SW.Size size)
{
// Calculates the desired size of widget.
if (!Widget.IsMeasureValid) {
try {
calculatingPreferredSize = true;
Widget.Measure (new System.Windows.Size (availableWidth, availableHeight));
}
finally {
calculatingPreferredSize = false;
gettingNaturalSize = false;
}
}
2013-05-31 11:44:45 +04:00
size = Widget.DesiredSize;
}
2013-05-31 11:44:45 +04:00
// The GetPreferredSize method is called when the corresponding OnGetPreferredSize method in the
// XWT widget is not overriden, or if it is overriden and the new implementation calls
// base.OnGetPreferredSize. For this reason, we have to ensure that the widget's MeasureOverride
// method doesn't end calling the frontend OnGetPreferredSize method. To avoid it we set
// the calculatingPreferredSize flag to true, and we check this flag in MeasureOverride
2013-05-31 11:44:45 +04:00
public virtual Size GetPreferredSize (SizeConstraint widthConstraint, SizeConstraint heightConstraint)
{
2013-05-31 11:44:45 +04:00
SW.Size size;
Widget.InvalidateMeasure ();
GetWidgetDesiredSize (widthConstraint.IsConstrained ? widthConstraint.AvailableSize : Double.PositiveInfinity, heightConstraint.IsConstrained ? heightConstraint.AvailableSize : Double.PositiveInfinity, out size);
2013-05-31 11:44:45 +04:00
return new Size (size.Width, size.Height);
}
/// <summary>
/// A default implementation of MeasureOverride to be used by all WPF widgets
/// </summary>
/// <param name="constraint">Size constraints</param>
/// <param name="wpfMeasure">Size returned by the base MeasureOverride</param>
/// <returns></returns>
public System.Windows.Size MeasureOverride (System.Windows.Size constraint, System.Windows.Size wpfMeasure)
{
2013-05-31 11:44:45 +04:00
var defNaturalSize = eventSink.GetDefaultNaturalSize ();
// -2 means use the WPF default, -1 use the XWT default, any other other value is used as custom natural size
var nw = DefaultNaturalWidth;
if (nw == -1) {
nw = defNaturalSize.Width;
if (nw == 0)
nw = wpfMeasure.Width;
wpfMeasure.Width = nw;
}
else if (nw != -2)
wpfMeasure.Width = nw;
var nh = DefaultNaturalHeight;
if (nh == -1) {
nh = defNaturalSize.Height;
if (nh == 0)
nh = wpfMeasure.Height;
wpfMeasure.Height = nh;
}
2013-05-31 11:44:45 +04:00
else if (nh != -2)
wpfMeasure.Height = nh;
// If we are calculating the default preferred size of the widget we end here.
// See note above about when GetPreferred* methods are called.
if (calculatingPreferredSize)
return wpfMeasure;
2013-05-31 11:44:45 +04:00
if ((enabledEvents & WidgetEvent.PreferredSizeCheck) != 0) {
Context.InvokeUserCode (delegate
{
2013-01-17 17:35:47 +04:00
// Calculate the preferred width through the frontend if there is an overriden OnGetPreferredWidth, but only do it
// if we are not given a constraint. If there is a width constraint, we'll use that constraint value for calculating the height
var cw = double.IsPositiveInfinity (constraint.Width) ? SizeConstraint.Unconstrained : constraint.Width;
var ch = double.IsPositiveInfinity (constraint.Height) ? SizeConstraint.Unconstrained : constraint.Height;
var ws = eventSink.GetPreferredSize (cw, ch);
2013-05-31 11:44:45 +04:00
wpfMeasure = new System.Windows.Size (ws.Width, ws.Height);
});
}
return wpfMeasure;
}
/// <summary>
/// Natural width for the widget. It can be any arbitrary custom value,
/// or -1 if the XWT defined default has to be used,
/// or -2 if the WPF desired size has to be used (this is the default)
/// </summary>
protected virtual double DefaultNaturalWidth {
get { return -2; }
}
/// <summary>
/// Natural width for the widget. It can be any arbitrary custom value,
/// or -1 if the XWT defined default has to be used,
/// or -2 if the WPF desired size has to be used (this is the default)
/// </summary>
protected virtual double DefaultNaturalHeight
{
get { return -2; }
}
2013-05-31 11:44:45 +04:00
public virtual void UpdateChildPlacement (IWidgetBackend childBackend)
{
2013-07-09 17:59:24 +04:00
SetChildPlacement (childBackend);
}
public static void SetChildPlacement (IWidgetBackend childBackend)
{
var w = ((WidgetBackend)childBackend);
w.Widget.Margin = new Thickness (w.Frontend.MarginLeft, w.Frontend.MarginTop, w.Frontend.MarginRight, w.Frontend.MarginBottom);
switch (w.Frontend.HorizontalPlacement) {
case WidgetPlacement.Start: w.Widget.HorizontalAlignment = HorizontalAlignment.Left; break;
case WidgetPlacement.Center: w.Widget.HorizontalAlignment = HorizontalAlignment.Center; break;
case WidgetPlacement.End: w.Widget.HorizontalAlignment = HorizontalAlignment.Right; break;
case WidgetPlacement.Fill: w.Widget.HorizontalAlignment = HorizontalAlignment.Stretch; break;
}
switch (w.Frontend.VerticalPlacement) {
case WidgetPlacement.Start: w.Widget.VerticalAlignment = VerticalAlignment.Top; break;
case WidgetPlacement.Center: w.Widget.VerticalAlignment = VerticalAlignment.Center; break;
case WidgetPlacement.End: w.Widget.VerticalAlignment = VerticalAlignment.Bottom; break;
case WidgetPlacement.Fill: w.Widget.VerticalAlignment = VerticalAlignment.Stretch; break;
}
2013-05-31 11:44:45 +04:00
}
public void SetMinSize (double width, double height)
{
if (width == -1)
Widget.ClearValue (FrameworkElement.MinWidthProperty);
else
Widget.MinWidth = width;
if (height == -1)
Widget.ClearValue (FrameworkElement.MinHeightProperty);
else
Widget.MinHeight = height;
}
public void SetSizeRequest (double width, double height)
{
// Nothing needs to be done here
}
public void SetCursor (CursorType cursor)
{
2012-04-04 02:41:29 +04:00
if (cursor == CursorType.Arrow)
Widget.Cursor = Cursors.Arrow;
else if (cursor == CursorType.Crosshair)
Widget.Cursor = Cursors.Cross;
else if (cursor == CursorType.Hand)
Widget.Cursor = Cursors.Hand;
else if (cursor == CursorType.IBeam)
Widget.Cursor = Cursors.IBeam;
else if (cursor == CursorType.ResizeDown)
Widget.Cursor = Cursors.SizeNS;
2012-04-04 02:41:29 +04:00
else if (cursor == CursorType.ResizeUp)
Widget.Cursor = Cursors.SizeNS;
2012-04-04 02:41:29 +04:00
else if (cursor == CursorType.ResizeUpDown)
Widget.Cursor = Cursors.SizeNS;
else if (cursor == CursorType.ResizeLeft)
Widget.Cursor = Cursors.SizeWE;
2012-04-04 02:41:29 +04:00
else if (cursor == CursorType.ResizeRight)
Widget.Cursor = Cursors.SizeWE;
2012-04-04 02:41:29 +04:00
else if (cursor == CursorType.ResizeLeftRight)
widget.Cursor = Cursors.SizeWE;
else if (cursor == CursorType.Move)
widget.Cursor = Cursors.SizeAll;
else if (cursor == CursorType.Wait)
widget.Cursor = Cursors.Wait;
else if (cursor == CursorType.Help)
widget.Cursor = Cursors.Help;
else
Widget.Cursor = Cursors.Arrow;
}
public virtual void UpdateLayout ()
{
}
public override void EnableEvent (object eventId)
{
if (eventId is WidgetEvent) {
var ev = (WidgetEvent)eventId;
switch (ev) {
case WidgetEvent.KeyPressed:
Widget.KeyDown += WidgetKeyDownHandler;
break;
case WidgetEvent.KeyReleased:
2013-03-12 03:53:36 +04:00
Widget.KeyUp += WidgetKeyUpHandler;
break;
case WidgetEvent.ButtonPressed:
Widget.MouseDown += WidgetMouseDownHandler;
break;
case WidgetEvent.ButtonReleased:
Widget.MouseUp += WidgetMouseUpHandler;
break;
case WidgetEvent.GotFocus:
Widget.GotFocus += WidgetGotFocusHandler;
break;
case WidgetEvent.LostFocus:
Widget.LostFocus += WidgetLostFocusHandler;
break;
case WidgetEvent.MouseEntered:
Widget.MouseEnter += WidgetMouseEnteredHandler;
break;
case WidgetEvent.MouseExited:
Widget.MouseLeave += WidgetMouseExitedHandler;
break;
2012-03-23 21:44:50 +04:00
case WidgetEvent.MouseMoved:
Widget.MouseMove += WidgetMouseMoveHandler;
break;
2012-03-16 21:09:35 +04:00
case WidgetEvent.BoundsChanged:
Widget.SizeChanged += WidgetOnSizeChanged;
break;
case WidgetEvent.MouseScrolled:
Widget.MouseWheel += WidgetMouseWheelHandler;
break;
}
if ((ev & dragDropEvents) != 0 && (enabledEvents & dragDropEvents) == 0) {
// Enabling a drag&drop event for the first time
Widget.DragOver += WidgetDragOverHandler;
Widget.Drop += WidgetDropHandler;
2012-06-09 02:55:29 +04:00
widget.DragLeave += WidgetDragLeaveHandler;
}
enabledEvents |= ev;
}
}
public override void DisableEvent (object eventId)
{
if (eventId is WidgetEvent) {
var ev = (WidgetEvent)eventId;
switch (ev) {
case WidgetEvent.KeyPressed:
Widget.KeyDown -= WidgetKeyDownHandler;
break;
case WidgetEvent.KeyReleased:
Widget.KeyUp -= WidgetKeyUpHandler;
break;
case WidgetEvent.ButtonPressed:
Widget.MouseDown -= WidgetMouseDownHandler;
break;
case WidgetEvent.ButtonReleased:
Widget.MouseUp -= WidgetMouseUpHandler;
break;
case WidgetEvent.MouseEntered:
Widget.MouseEnter -= WidgetMouseEnteredHandler;
break;
case WidgetEvent.MouseExited:
Widget.MouseLeave -= WidgetMouseExitedHandler;
break;
2012-03-23 21:44:50 +04:00
case WidgetEvent.MouseMoved:
Widget.MouseMove -= WidgetMouseMoveHandler;
break;
2012-03-16 21:09:35 +04:00
case WidgetEvent.BoundsChanged:
Widget.SizeChanged -= WidgetOnSizeChanged;
break;
case WidgetEvent.MouseScrolled:
Widget.MouseWheel -= WidgetMouseWheelHandler;
break;
}
enabledEvents &= ~ev;
if ((ev & dragDropEvents) != 0 && (enabledEvents & dragDropEvents) == 0) {
// All drag&drop events have been disabled
Widget.DragOver -= WidgetDragOverHandler;
Widget.Drop -= WidgetDropHandler;
2012-06-09 02:55:29 +04:00
Widget.DragLeave -= WidgetDragLeaveHandler;
}
}
}
public double aWidthPixelRatio
2012-03-09 23:40:40 +04:00
{
get
{
PresentationSource source = PresentationSource.FromVisual (Widget);
if (source == null)
return 1;
Matrix m = source.CompositionTarget.TransformToDevice;
return m.M11;
}
}
public double aHeightPixelRatio
2012-03-09 23:40:40 +04:00
{
get
{
PresentationSource source = PresentationSource.FromVisual (Widget);
if (source == null)
return 1;
Matrix m = source.CompositionTarget.TransformToDevice;
return m.M22;
}
}
void WidgetKeyDownHandler (object sender, System.Windows.Input.KeyEventArgs e)
{
KeyEventArgs args;
if (MapToXwtKeyArgs (e, out args)) {
2012-12-07 16:12:39 +04:00
Context.InvokeUserCode (delegate {
eventSink.OnKeyPressed (args);
});
2012-05-10 15:25:56 +04:00
if (args.Handled)
e.Handled = true;
}
}
void WidgetKeyUpHandler (object sender, System.Windows.Input.KeyEventArgs e)
{
KeyEventArgs args;
if (MapToXwtKeyArgs (e, out args)) {
2012-12-07 16:12:39 +04:00
Context.InvokeUserCode (delegate
{
eventSink.OnKeyReleased (args);
});
2012-05-10 15:25:56 +04:00
if (args.Handled)
e.Handled = true;
}
}
bool MapToXwtKeyArgs (System.Windows.Input.KeyEventArgs e, out KeyEventArgs result)
{
result = null;
var key = KeyboardUtil.TranslateToXwtKey (e.Key);
if ((int)key == 0)
return false;
result = new KeyEventArgs (key, KeyboardUtil.GetModifiers (), e.IsRepeat, e.Timestamp);
return true;
}
void WidgetMouseDownHandler (object o, MouseButtonEventArgs e)
{
2012-05-10 15:25:56 +04:00
var args = ToXwtButtonArgs (e);
2012-12-07 16:12:39 +04:00
Context.InvokeUserCode (delegate () {
2012-05-10 15:25:56 +04:00
eventSink.OnButtonPressed (args);
});
2012-05-10 15:25:56 +04:00
if (args.Handled)
e.Handled = true;
}
void WidgetMouseUpHandler (object o, MouseButtonEventArgs e)
{
2012-05-10 15:25:56 +04:00
var args = ToXwtButtonArgs (e);
2012-12-07 16:12:39 +04:00
Context.InvokeUserCode (delegate ()
{
2012-05-10 15:25:56 +04:00
eventSink.OnButtonReleased (args);
});
2012-05-10 15:25:56 +04:00
if (args.Handled)
e.Handled = true;
}
ButtonEventArgs ToXwtButtonArgs (MouseButtonEventArgs e)
{
var pos = e.GetPosition (Widget);
return new ButtonEventArgs () {
X = pos.X,
Y = pos.Y,
MultiplePress = e.ClickCount,
Button = e.ChangedButton.ToXwtButton ()
};
}
void WidgetGotFocusHandler (object o, RoutedEventArgs e)
{
2012-12-07 16:12:39 +04:00
Context.InvokeUserCode (this.eventSink.OnGotFocus);
}
void WidgetLostFocusHandler (object o, RoutedEventArgs e)
{
2012-12-07 16:12:39 +04:00
Context.InvokeUserCode (eventSink.OnLostFocus);
}
DragDropData DragDropInfo {
get {
if (dragDropInfo == null)
dragDropInfo = new DragDropData ();
return dragDropInfo;
}
}
private static ImageAdorner Adorner;
private static AdornerLayer AdornedLayer;
private static System.Windows.Window AdornedWindow;
private SW.Window GetParentWindow()
{
FrameworkElement current = Widget;
while (current != null) {
if (current is SW.Window)
return (SW.Window)current;
current = VisualTreeHelper.GetParent (current) as FrameworkElement;
}
return null;
}
public void DragStart (DragStartData data)
{
if (data.Data == null)
throw new ArgumentNullException ("data");
2012-04-24 01:56:34 +04:00
DataObject dataObj = data.Data.ToDataObject();
2012-04-24 01:56:34 +04:00
if (data.ImageBackend != null) {
AdornedWindow = GetParentWindow ();
AdornedWindow.AllowDrop = true;
var e = (UIElement)AdornedWindow.Content;
Adorner = new ImageAdorner (e, data.ImageBackend);
AdornedLayer = AdornerLayer.GetAdornerLayer (e);
AdornedLayer.Add (Adorner);
AdornedWindow.DragOver += AdornedWindowOnDragOver;
2012-04-24 01:56:34 +04:00
}
Widget.Dispatcher.BeginInvoke ((Action)(() => {
var effect = DragDrop.DoDragDrop (Widget, dataObj, data.DragAction.ToWpfDropEffect ());
2012-06-09 02:55:29 +04:00
OnDragFinished (this, new DragFinishedEventArgs (effect == DragDropEffects.Move));
if (Adorner != null) {
AdornedLayer.Remove (Adorner);
AdornedLayer = null;
Adorner = null;
AdornedWindow.AllowDrop = false;
AdornedWindow.DragOver -= AdornedWindowOnDragOver;
AdornedWindow = null;
}
}));
}
private void AdornedWindowOnDragOver (object sender, System.Windows.DragEventArgs e)
{
WidgetDragOverHandler (sender, e);
}
public void SetDragTarget (TransferDataType [] types, DragDropAction dragAction)
{
DragDropInfo.TargetTypes = types == null ? new TransferDataType [0] : types;
Widget.AllowDrop = true;
}
public void SetDragSource (TransferDataType [] types, DragDropAction dragAction)
{
if (DragDropInfo.AutodetectDrag)
return; // Drag auto detect has been already activated.
DragDropInfo.AutodetectDrag = true;
Widget.MouseUp += WidgetMouseUpForDragHandler;
Widget.MouseMove += WidgetMouseMoveForDragHandler;
}
private void SetupDragRect (MouseEventArgs e)
{
var width = SystemParameters.MinimumHorizontalDragDistance;
var height = SystemParameters.MinimumVerticalDragDistance;
var loc = e.GetPosition (Widget);
DragDropInfo.DragRect = new Rect (loc.X - width / 2, loc.Y - height / 2, width, height);
}
void WidgetMouseUpForDragHandler (object o, EventArgs e)
{
DragDropInfo.DragRect = Rect.Empty;
}
void WidgetMouseMoveForDragHandler (object o, MouseEventArgs e)
{
if ((enabledEvents & WidgetEvent.DragStarted) == 0)
return;
if (e.LeftButton != MouseButtonState.Pressed)
return;
if (DragDropInfo.DragRect.IsEmpty)
SetupDragRect (e);
if (DragDropInfo.DragRect.Contains (e.GetPosition (Widget)))
return;
DragStartData dragData = null;
2012-12-07 16:12:39 +04:00
Context.InvokeUserCode (delegate {
dragData = eventSink.OnDragStarted ();
});
if (dragData != null)
DragStart (dragData);
DragDropInfo.DragRect = Rect.Empty;
}
static DragDropAction DetectDragAction (DragDropKeyStates keys)
{
if ((keys & DragDropKeyStates.ControlKey) == DragDropKeyStates.ControlKey) {
if ((keys & DragDropKeyStates.ShiftKey) == DragDropKeyStates.ShiftKey)
return DragDropAction.Link;
else
return DragDropAction.Copy;
}
return DragDropAction.Move;
}
static void FillDataStore (TransferDataStore store, IDataObject data, TransferDataType [] types)
{
foreach (var type in types) {
string format = type.ToWpfDataFormat ();
if (!data.GetDataPresent (format)) {
// This is a workaround to support type names which don't include the assembly name.
// It eases integration with Windows DND.
format = NormalizeTypeName (format);
if (!data.GetDataPresent (format))
continue;
}
var value = data.GetData (format);
if (type == TransferDataType.Text)
store.AddText ((string)value);
else if (type == TransferDataType.Uri) {
var uris = ((string [])value).Select (f => new Uri (f)).ToArray ();
store.AddUris (uris);
2012-04-12 20:10:54 +04:00
} else if (value is byte[])
store.AddValue (type, (byte[]) value);
else
store.AddValue (type, value);
}
}
static string NormalizeTypeName (string dataType)
{
// If the string is a fully qualified type name, strip the assembly name
int i = dataType.IndexOf (',');
if (i == -1)
return dataType;
string asmName = dataType.Substring (i + 1).Trim ();
try {
new System.Reflection.AssemblyName (asmName);
}
catch {
return dataType;
}
return dataType.Substring (0, i).Trim ();
}
2012-06-09 02:55:29 +04:00
protected virtual void OnDragFinished (object sender, DragFinishedEventArgs e)
{
2012-12-07 16:12:39 +04:00
Context.InvokeUserCode (delegate {
2012-06-09 02:55:29 +04:00
this.eventSink.OnDragFinished (e);
});
}
protected virtual void OnDragOver (object sender, DragOverEventArgs e)
{
2012-12-07 16:12:39 +04:00
Context.InvokeUserCode (delegate {
2012-06-09 02:55:29 +04:00
eventSink.OnDragOver (e);
});
}
protected virtual void OnDragLeave (object sender, EventArgs e)
{
2012-12-07 16:12:39 +04:00
Context.InvokeUserCode (delegate {
2012-06-09 02:55:29 +04:00
eventSink.OnDragLeave (e);
});
}
void WidgetDragOverHandler (object sender, System.Windows.DragEventArgs e)
{
if (Adorner != null) {
var w = GetParentWindow ();
var v = (UIElement)w.Content;
if (w != AdornedWindow) {
AdornedLayer.Remove (Adorner);
AdornedWindow.AllowDrop = false;
AdornedWindow.DragOver -= AdornedWindowOnDragOver;
AdornedWindow = w;
AdornedWindow.AllowDrop = true;
AdornedWindow.DragOver += AdornedWindowOnDragOver;
AdornedLayer = AdornerLayer.GetAdornerLayer (v);
AdornedLayer.Add (Adorner);
}
Adorner.Offset = e.GetPosition (v);
}
CheckDrop (sender, e);
}
void CheckDrop (object sender, System.Windows.DragEventArgs e)
{
var types = e.Data.GetFormats ().Select (t => t.ToXwtTransferType ()).ToArray ();
var pos = e.GetPosition (Widget).ToXwtPoint ();
var proposedAction = DetectDragAction (e.KeyStates);
e.Handled = true; // Prevent default handlers from being used.
2012-04-24 01:56:34 +04:00
if ((enabledEvents & WidgetEvent.DragOverCheck) > 0) {
var checkArgs = new DragOverCheckEventArgs (pos, types, proposedAction);
2012-12-07 16:12:39 +04:00
Context.InvokeUserCode (delegate {
eventSink.OnDragOverCheck (checkArgs);
});
if (checkArgs.AllowedAction == DragDropAction.None) {
e.Effects = currentDragEffect = DragDropEffects.None;
return;
}
if (checkArgs.AllowedAction != DragDropAction.Default) {
e.Effects = currentDragEffect = checkArgs.AllowedAction.ToWpfDropEffect ();
return;
}
}
if ((enabledEvents & WidgetEvent.DragOver) > 0) {
var store = new TransferDataStore ();
FillDataStore (store, e.Data, DragDropInfo.TargetTypes);
var args = new DragOverEventArgs (pos, store, proposedAction);
2012-06-09 02:55:29 +04:00
OnDragOver (sender, args);
if (args.AllowedAction == DragDropAction.None) {
e.Effects = currentDragEffect = DragDropEffects.None;
return;
}
if (args.AllowedAction != DragDropAction.Default) {
e.Effects = currentDragEffect = args.AllowedAction.ToWpfDropEffect ();
return;
}
}
e.Effects = currentDragEffect = proposedAction.ToWpfDropEffect ();
}
void WidgetDropHandler (object sender, System.Windows.DragEventArgs e)
{
// Do a DragOverCheck before proceeding to the drop. This is required since in some cases the DragOver
// handler may not be called.
CheckDrop (sender, e);
if (e.Effects == DragDropEffects.None)
return;
WidgetDragLeaveHandler (sender, e);
var types = e.Data.GetFormats ().Select (t => t.ToXwtTransferType ()).ToArray ();
var pos = e.GetPosition (Widget).ToXwtPoint ();
var actualEffect = currentDragEffect;
e.Handled = true; // Prevent default handlers from being used.
e.Effects = DragDropEffects.None;
if ((enabledEvents & WidgetEvent.DragDropCheck) > 0) {
var checkArgs = new DragCheckEventArgs (pos, types, actualEffect.ToXwtDropAction ());
2012-12-07 16:12:39 +04:00
bool res = Context.InvokeUserCode (delegate {
eventSink.OnDragDropCheck (checkArgs);
});
if (checkArgs.Result == DragDropResult.Canceled || !res) {
e.Effects = DragDropEffects.None;
return;
}
}
if ((enabledEvents & WidgetEvent.DragDrop) > 0) {
var store = new TransferDataStore ();
FillDataStore (store, e.Data, DragDropInfo.TargetTypes);
var args = new DragEventArgs (pos, store, actualEffect.ToXwtDropAction ());
2012-12-07 16:12:39 +04:00
Context.InvokeUserCode (delegate {
eventSink.OnDragDrop (args);
});
if (args.Success)
e.Effects = actualEffect;
}
}
void WidgetDragLeaveHandler (object sender, System.Windows.DragEventArgs e)
{
2012-06-09 02:55:29 +04:00
OnDragLeave (sender, e);
}
private void WidgetMouseEnteredHandler (object sender, MouseEventArgs e)
{
2012-12-07 16:12:39 +04:00
Context.InvokeUserCode (eventSink.OnMouseEntered);
}
private void WidgetMouseExitedHandler (object sender, MouseEventArgs e)
{
2012-12-07 16:12:39 +04:00
Context.InvokeUserCode (eventSink.OnMouseExited);
}
2012-03-16 21:09:35 +04:00
2012-03-23 21:44:50 +04:00
private void WidgetMouseMoveHandler (object sender, MouseEventArgs e)
{
var p = e.GetPosition (Widget);
var a = new MouseMovedEventArgs(e.Timestamp, p.X, p.Y);
2012-12-07 16:12:39 +04:00
Context.InvokeUserCode (() => {
eventSink.OnMouseMoved(a);
2012-03-23 21:44:50 +04:00
});
if (a.Handled)
e.Handled = true;
2012-03-23 21:44:50 +04:00
}
private int mouseScrollCumulation = 0;
private void WidgetMouseWheelHandler (object sender, MouseWheelEventArgs e)
{
mouseScrollCumulation += e.Delta;
int jumps = mouseScrollCumulation / 120;
mouseScrollCumulation %= 120;
var p = e.GetPosition(Widget);
2012-12-07 16:12:39 +04:00
Context.InvokeUserCode (delegate {
for (int i = 0; i < jumps; i++) {
var a = new MouseScrolledEventArgs(e.Timestamp, p.X, p.Y, ScrollDirection.Up);
eventSink.OnMouseScrolled(a);
if (a.Handled)
e.Handled = true;
}
for (int i = 0; i > jumps; i--) {
var a = new MouseScrolledEventArgs(e.Timestamp, p.X, p.Y, ScrollDirection.Down);
eventSink.OnMouseScrolled(a);
if (a.Handled)
e.Handled = true;
}
});
}
2012-03-16 21:09:35 +04:00
private void WidgetOnSizeChanged (object sender, SizeChangedEventArgs e)
{
if (Widget.IsVisible)
2012-12-07 16:12:39 +04:00
Context.InvokeUserCode (this.eventSink.OnBoundsChanged);
2012-03-16 21:09:35 +04:00
}
}
public interface IWpfWidgetBackend
{
FrameworkElement Widget { get; }
}
public interface IWpfWidget
{
WidgetBackend Backend { get; set; }
}
}