5
// Carlos Alberto Cortez <calberto.cortez@gmail.com>
6
// Eric Maupin <ermau@xamarin.com>
8
// Copyright (c) 2011 Carlos Alberto Cortez
9
// Copyright (c) 2012 Xamarin, Inc.
11
// Permission is hereby granted, free of charge, to any person obtaining a copy
12
// of this software and associated documentation files (the "Software"), to deal
13
// in the Software without restriction, including without limitation the rights
14
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
// copies of the Software, and to permit persons to whom the Software is
16
// furnished to do so, subject to the following conditions:
18
// The above copyright notice and this permission notice shall be included in
19
// all copies or substantial portions of the Software.
21
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30
using System.Collections.Specialized;
33
using System.Windows.Controls;
34
using System.Windows.Documents;
35
using System.Windows.Input;
36
using System.Windows.Media;
37
using SWM = System.Windows.Media;
38
using SWC = System.Windows.Controls; // When we need to resolve ambigituies.
39
using SW = System.Windows; // When we need to resolve ambigituies.
43
using Color = Xwt.Drawing.Color;
45
namespace Xwt.WPFBackend
47
public abstract class WidgetBackend
48
: Backend, IWidgetBackend, IWpfWidgetBackend
50
IWidgetEventSink eventSink;
51
WidgetEvent enabledEvents;
52
DragDropEffects currentDragEffect;
53
FrameworkElement widget;
58
public bool AutodetectDrag;
61
public TransferDataType [] TargetTypes = new TransferDataType [0];
64
DragDropData dragDropInfo;
66
const WidgetEvent dragDropEvents = WidgetEvent.DragDropCheck | WidgetEvent.DragDrop | WidgetEvent.DragOver | WidgetEvent.DragOverCheck;
68
// Set to true when measuring a natural size for this widget
69
bool gettingNaturalSize;
71
// Set to true when calculating the default preferred size of the widget
72
bool calculatingPreferredSize;
74
void IWidgetBackend.Initialize (IWidgetEventSink eventSink)
76
this.eventSink = eventSink;
80
protected virtual void Initialize ()
89
public void Dispose ()
91
GC.SuppressFinalize (this);
95
protected virtual void Dispose (bool disposing)
99
public IWidgetEventSink EventSink {
100
get { return eventSink; }
103
public object NativeWidget {
104
get { return Widget; }
107
public new Widget Frontend {
108
get { return (Widget) base.Frontend; }
111
public FrameworkElement Widget {
112
get { return widget; }
116
if (widget is IWpfWidget)
117
((IWpfWidget)widget).Backend = this;
118
widget.InvalidateMeasure ();
122
Color? customBackgroundColor;
124
public virtual Color BackgroundColor {
126
if (customBackgroundColor.HasValue)
127
return customBackgroundColor.Value;
129
return DataConverter.ToXwtColor (GetWidgetColor ());
132
customBackgroundColor = value;
133
SetWidgetColor (value);
137
SWM.Color GetWidgetColor ()
139
if (Widget is Control) {
140
var control = (Control)Widget;
141
if (control.Background != null)
142
return ((SWM.SolidColorBrush)control.Background).Color;
143
} else if (Widget is SWC.Panel) {
144
var panel = (SWC.Panel)Widget;
145
if (panel.Background != null)
146
return ((SWM.SolidColorBrush)panel.Background).Color;
149
return SystemColors.ControlColor;
152
void SetWidgetColor (Color value)
154
if ((Widget is Control))
155
((Control)Widget).Background = ResPool.GetSolidBrush (value);
156
if ((Widget is System.Windows.Controls.Panel))
157
((SWC.Panel)Widget).Background = ResPool.GetSolidBrush (value);
160
public bool UsingCustomBackgroundColor {
161
get { return customBackgroundColor.HasValue; }
164
public virtual object Font {
165
get { return GetWidgetFont (); }
167
SetWidgetFont ((FontData)value);
171
FontData GetWidgetFont ()
173
if (!(Widget is Control)) {
174
double size = FontBackendHandler.GetPointsFromDeviceUnits (SystemFonts.MessageFontSize);
176
return new FontData (SystemFonts.MessageFontFamily, size, Drawing.FontSizeUnit.Points) {
177
Style = SystemFonts.MessageFontStyle,
178
Weight = SystemFonts.MessageFontWeight
182
return FontData.FromControl ((Control)Widget);
185
void SetWidgetFont (FontData font)
187
if (!(Widget is Control))
190
var control = (Control)Widget;
191
control.FontFamily = font.Family;
192
control.FontSize = font.GetDeviceIndependentPixelSize (control);
193
control.FontStyle = font.Style;
194
control.FontWeight = font.Weight;
195
control.FontStretch = font.Stretch;
198
public bool CanGetFocus {
199
get { return Widget.Focusable; }
200
set { Widget.Focusable = value; }
203
public bool HasFocus {
204
get { return Widget.IsFocused; }
207
public void SetFocus ()
212
public virtual bool Sensitive {
213
get { return Widget.IsEnabled; }
214
set { Widget.IsEnabled = value; }
218
get { return new Size (Widget.ActualWidth, Widget.ActualHeight); }
221
public virtual bool Visible {
222
get { return Widget.Visibility == Visibility.Visible; }
223
set { Widget.Visibility = value ? Visibility.Visible : Visibility.Collapsed; }
226
public string TooltipText {
227
get { return Widget.ToolTip.ToString (); }
228
set { Widget.ToolTip = value; }
231
public static FrameworkElement GetFrameworkElement (IWidgetBackend backend)
233
return backend == null ? null : (FrameworkElement)backend.NativeWidget;
236
public Point ConvertToScreenCoordinates (Point widgetCoordinates)
238
double wratio = WidthPixelRatio;
239
double hratio = HeightPixelRatio;
241
var p = Widget.PointToScreen (new System.Windows.Point (
242
widgetCoordinates.X / wratio, widgetCoordinates.Y / hratio));
244
return new Point (p.X * wratio, p.Y * hratio);
247
SW.Size lastNaturalSize;
249
void GetWidgetDesiredSize (double availableWidth, double availableHeight, out SW.Size minSize, out SW.Size naturalSize)
251
// Calculates the desired size of widget.
253
if (!Widget.IsMeasureValid) {
255
calculatingPreferredSize = true;
256
gettingNaturalSize = true;
257
Widget.Measure (new System.Windows.Size (availableWidth, availableHeight));
258
lastNaturalSize = Widget.DesiredSize;
259
gettingNaturalSize = false;
261
Widget.InvalidateMeasure ();
262
Widget.Measure (new System.Windows.Size (availableWidth, availableHeight));
265
calculatingPreferredSize = false;
266
gettingNaturalSize = false;
269
minSize = Widget.DesiredSize;
270
naturalSize = lastNaturalSize;
273
// The GetPreferred* methods are called when the corresponding OnGetPreferred* methods in the
274
// XWT widget are not overriden, or if they are overriden and the new implementation calls
275
// base.OnGetPreferred*. For this reason, we have to ensure that the widget's MeasureOverride
276
// method doesn't end calling the frontend OnGetPreferred* methods. To avoid it we set
277
// the calculatingPreferredSize flag to true, and we check this flag in MeasureOverride
279
public virtual WidgetSize GetPreferredWidth ()
281
SW.Size minSize, natSize;
282
Widget.InvalidateMeasure ();
283
GetWidgetDesiredSize (Double.PositiveInfinity, Double.PositiveInfinity, out minSize, out natSize);
284
return new WidgetSize (minSize.Width * WidthPixelRatio - Frontend.Margin.HorizontalSpacing, natSize.Width * WidthPixelRatio - Frontend.Margin.HorizontalSpacing);
287
public virtual WidgetSize GetPreferredHeight ()
289
SW.Size minSize, natSize;
290
Widget.InvalidateMeasure ();
291
GetWidgetDesiredSize (Double.PositiveInfinity, Double.PositiveInfinity, out minSize, out natSize);
292
return new WidgetSize (minSize.Height * WidthPixelRatio - Frontend.Margin.VerticalSpacing, natSize.Height * HeightPixelRatio - Frontend.Margin.VerticalSpacing);
295
public virtual WidgetSize GetPreferredWidthForHeight (double height)
297
SW.Size minSize, natSize;
298
Widget.InvalidateMeasure ();
299
GetWidgetDesiredSize (Double.PositiveInfinity, height, out minSize, out natSize);
300
return new WidgetSize (minSize.Width * WidthPixelRatio - Frontend.Margin.HorizontalSpacing, natSize.Width * WidthPixelRatio - Frontend.Margin.HorizontalSpacing);
303
public virtual WidgetSize GetPreferredHeightForWidth (double width)
305
SW.Size minSize, natSize;
306
Widget.InvalidateMeasure ();
307
GetWidgetDesiredSize (width, Double.PositiveInfinity, out minSize, out natSize);
308
return new WidgetSize (minSize.Height * HeightPixelRatio - Frontend.Margin.VerticalSpacing, natSize.Height * HeightPixelRatio - Frontend.Margin.VerticalSpacing);
312
/// A default implementation of MeasureOverride to be used by all WPF widgets
314
/// <param name="constraint">Size constraints</param>
315
/// <param name="wpfMeasure">Size returned by the base MeasureOverride</param>
316
/// <returns></returns>
317
public System.Windows.Size MeasureOverride (System.Windows.Size constraint, System.Windows.Size wpfMeasure)
319
// Calculate the natural size, if that's what is being measured
321
if (gettingNaturalSize) {
322
var defNaturalSize = eventSink.GetDefaultNaturalSize ();
324
// -2 means use the WPF default, -1 use the XWT default, any other other value is used as custom natural size
325
var nw = DefaultNaturalWidth;
327
nw = defNaturalSize.Width;
329
nw = wpfMeasure.Width;
330
wpfMeasure.Width = nw;
333
wpfMeasure.Width = nw;
335
var nh = DefaultNaturalHeight;
337
nh = defNaturalSize.Height;
339
nh = wpfMeasure.Height;
340
wpfMeasure.Height = nh;
343
wpfMeasure.Height = nh;
346
// If we are calculating the default preferred size of the widget we end here.
347
// See note above about when GetPreferred* methods are called.
348
if (calculatingPreferredSize)
351
Toolkit.Invoke (delegate
353
if (eventSink.GetSizeRequestMode () == SizeRequestMode.HeightForWidth) {
354
// Calculate the preferred width through the frontend if there is an overriden OnGetPreferredWidth, but only do it
355
// if we are not given a constraint. If there is a width constraint, we'll use that constraint value for calculating the height
356
if ((enabledEvents & WidgetEvent.PreferredWidthCheck) != 0 && constraint.Width == Double.PositiveInfinity) {
357
var ws = eventSink.OnGetPreferredWidth ();
358
wpfMeasure.Width = constraint.Width = gettingNaturalSize ? ws.NaturalSize : ws.MinSize;
361
// Now calculate the preferred height for that width, also using the override if available
362
if ((enabledEvents & WidgetEvent.PreferredHeightForWidthCheck) != 0) {
363
var ws = eventSink.OnGetPreferredHeightForWidth (constraint.Width);
364
wpfMeasure.Height = gettingNaturalSize ? ws.NaturalSize : ws.MinSize;
368
// Calculate the preferred height through the frontend, if there is an overriden OnGetPreferredHeight
369
if ((enabledEvents & WidgetEvent.PreferredHeightCheck) != 0 && constraint.Height == Double.PositiveInfinity) {
370
var ws = eventSink.OnGetPreferredHeight ();
371
wpfMeasure.Height = constraint.Height = gettingNaturalSize ? ws.NaturalSize : ws.MinSize;
374
// Now calculate the preferred width for that height, also using the override if available
375
if ((enabledEvents & WidgetEvent.PreferredWidthForHeightCheck) != 0) {
376
var ws = eventSink.OnGetPreferredWidthForHeight (constraint.Height);
377
wpfMeasure.Width = gettingNaturalSize ? ws.NaturalSize : ws.MinSize;
385
/// Natural width for the widget. It can be any arbitrary custom value,
386
/// or -1 if the XWT defined default has to be used,
387
/// or -2 if the WPF desired size has to be used (this is the default)
389
protected virtual double DefaultNaturalWidth {
394
/// Natural width for the widget. It can be any arbitrary custom value,
395
/// or -1 if the XWT defined default has to be used,
396
/// or -2 if the WPF desired size has to be used (this is the default)
398
protected virtual double DefaultNaturalHeight
403
public void SetMinSize (double width, double height)
406
Widget.ClearValue (FrameworkElement.MinWidthProperty);
408
Widget.MinWidth = width / WidthPixelRatio;
411
Widget.ClearValue (FrameworkElement.MinHeightProperty);
413
Widget.MinHeight = height / HeightPixelRatio;
416
public void SetNaturalSize (double width, double height)
419
Widget.ClearValue (FrameworkElement.WidthProperty);
421
Widget.Width = width / WidthPixelRatio;
424
Widget.ClearValue (FrameworkElement.HeightProperty);
426
Widget.Height = height / HeightPixelRatio;
429
public void SetCursor (CursorType cursor)
431
if (cursor == CursorType.Arrow)
432
Widget.Cursor = Cursors.Arrow;
433
else if (cursor == CursorType.Crosshair)
434
Widget.Cursor = Cursors.Cross;
435
else if (cursor == CursorType.Hand)
436
Widget.Cursor = Cursors.Hand;
437
else if (cursor == CursorType.IBeam)
438
Widget.Cursor = Cursors.IBeam;
439
else if (cursor == CursorType.ResizeDown)
440
Widget.Cursor = Cursors.SizeNS;
441
else if (cursor == CursorType.ResizeUp)
442
Widget.Cursor = Cursors.SizeNS;
443
else if (cursor == CursorType.ResizeUpDown)
444
Widget.Cursor = Cursors.SizeNS;
445
else if (cursor == CursorType.ResizeLeft)
446
Widget.Cursor = Cursors.SizeWE;
447
else if (cursor == CursorType.ResizeRight)
448
Widget.Cursor = Cursors.SizeWE;
449
else if (cursor == CursorType.ResizeLeftRight)
450
widget.Cursor = Cursors.SizeWE;
453
public virtual void UpdateLayout ()
455
Xwt.Widget frontend = (Xwt.Widget)Frontend;
456
widget.Margin = new Thickness (frontend.Margin.Left, frontend.Margin.Top, frontend.Margin.Right, frontend.Margin.Bottom);
459
public override void EnableEvent (object eventId)
461
if (eventId is WidgetEvent) {
462
var ev = (WidgetEvent)eventId;
464
case WidgetEvent.KeyPressed:
465
Widget.KeyDown += WidgetKeyDownHandler;
467
case WidgetEvent.KeyReleased:
468
Widget.KeyDown += WidgetKeyUpHandler;
470
case WidgetEvent.ButtonPressed:
471
Widget.MouseDown += WidgetMouseDownHandler;
473
case WidgetEvent.ButtonReleased:
474
Widget.MouseUp += WidgetMouseUpHandler;
476
case WidgetEvent.GotFocus:
477
Widget.GotFocus += WidgetGotFocusHandler;
479
case WidgetEvent.LostFocus:
480
Widget.LostFocus += WidgetLostFocusHandler;
482
case WidgetEvent.MouseEntered:
483
Widget.MouseEnter += WidgetMouseEnteredHandler;
485
case WidgetEvent.MouseExited:
486
Widget.MouseLeave += WidgetMouseExitedHandler;
488
case WidgetEvent.MouseMoved:
489
Widget.MouseMove += WidgetMouseMoveHandler;
491
case WidgetEvent.BoundsChanged:
492
Widget.SizeChanged += WidgetOnSizeChanged;
494
case WidgetEvent.MouseScrolled:
495
Widget.MouseWheel += WidgetMouseWheelHandler;
499
if ((ev & dragDropEvents) != 0 && (enabledEvents & dragDropEvents) == 0) {
500
// Enabling a drag&drop event for the first time
501
Widget.DragOver += WidgetDragOverHandler;
502
Widget.Drop += WidgetDropHandler;
503
widget.DragLeave += WidgetDragLeaveHandler;
510
public override void DisableEvent (object eventId)
512
if (eventId is WidgetEvent) {
513
var ev = (WidgetEvent)eventId;
515
case WidgetEvent.KeyPressed:
516
Widget.KeyDown -= WidgetKeyDownHandler;
518
case WidgetEvent.KeyReleased:
519
Widget.KeyUp -= WidgetKeyUpHandler;
521
case WidgetEvent.ButtonPressed:
522
Widget.MouseDown -= WidgetMouseDownHandler;
524
case WidgetEvent.ButtonReleased:
525
Widget.MouseUp -= WidgetMouseUpHandler;
527
case WidgetEvent.MouseEntered:
528
Widget.MouseEnter -= WidgetMouseEnteredHandler;
530
case WidgetEvent.MouseExited:
531
Widget.MouseLeave -= WidgetMouseExitedHandler;
533
case WidgetEvent.MouseMoved:
534
Widget.MouseMove -= WidgetMouseMoveHandler;
536
case WidgetEvent.BoundsChanged:
537
Widget.SizeChanged -= WidgetOnSizeChanged;
539
case WidgetEvent.MouseScrolled:
540
Widget.MouseWheel -= WidgetMouseWheelHandler;
544
enabledEvents &= ~ev;
546
if ((ev & dragDropEvents) != 0 && (enabledEvents & dragDropEvents) == 0) {
547
// All drag&drop events have been disabled
548
Widget.DragOver -= WidgetDragOverHandler;
549
Widget.Drop -= WidgetDropHandler;
550
Widget.DragLeave -= WidgetDragLeaveHandler;
555
protected double WidthPixelRatio
559
PresentationSource source = PresentationSource.FromVisual (Widget);
563
Matrix m = source.CompositionTarget.TransformToDevice;
568
protected double HeightPixelRatio
572
PresentationSource source = PresentationSource.FromVisual (Widget);
576
Matrix m = source.CompositionTarget.TransformToDevice;
583
get { return WidthPixelRatio * 96; }
586
void WidgetKeyDownHandler (object sender, System.Windows.Input.KeyEventArgs e)
589
if (MapToXwtKeyArgs (e, out args)) {
590
Toolkit.Invoke (delegate {
591
eventSink.OnKeyPressed (args);
598
void WidgetKeyUpHandler (object sender, System.Windows.Input.KeyEventArgs e)
601
if (MapToXwtKeyArgs (e, out args)) {
602
Toolkit.Invoke (delegate {
603
eventSink.OnKeyReleased (args);
610
bool MapToXwtKeyArgs (System.Windows.Input.KeyEventArgs e, out KeyEventArgs result)
614
var key = KeyboardUtil.TranslateToXwtKey (e.Key);
618
result = new KeyEventArgs (key, KeyboardUtil.GetModifiers (), e.IsRepeat, e.Timestamp);
622
void WidgetMouseDownHandler (object o, MouseButtonEventArgs e)
624
var args = ToXwtButtonArgs (e);
625
Toolkit.Invoke (delegate () {
626
eventSink.OnButtonPressed (args);
632
void WidgetMouseUpHandler (object o, MouseButtonEventArgs e)
634
var args = ToXwtButtonArgs (e);
635
Toolkit.Invoke (delegate () {
636
eventSink.OnButtonReleased (args);
642
ButtonEventArgs ToXwtButtonArgs (MouseButtonEventArgs e)
644
var pos = e.GetPosition (Widget);
645
return new ButtonEventArgs () {
646
X = pos.X * WidthPixelRatio,
647
Y = pos.Y * HeightPixelRatio,
648
MultiplePress = e.ClickCount,
649
Button = e.ChangedButton.ToXwtButton ()
653
void WidgetGotFocusHandler (object o, RoutedEventArgs e)
655
Toolkit.Invoke (this.eventSink.OnGotFocus);
658
void WidgetLostFocusHandler (object o, RoutedEventArgs e)
660
Toolkit.Invoke (eventSink.OnLostFocus);
663
DragDropData DragDropInfo {
665
if (dragDropInfo == null)
666
dragDropInfo = new DragDropData ();
672
private static ImageAdorner Adorner;
673
private static AdornerLayer AdornedLayer;
674
private static System.Windows.Window AdornedWindow;
676
private SW.Window GetParentWindow()
678
FrameworkElement current = Widget;
679
while (current != null) {
680
if (current is SW.Window)
681
return (SW.Window)current;
683
current = VisualTreeHelper.GetParent (current) as FrameworkElement;
689
public void DragStart (DragStartData data)
691
if (data.Data == null)
692
throw new ArgumentNullException ("data");
694
DataObject dataObj = data.Data.ToDataObject();
696
if (data.ImageBackend != null) {
697
AdornedWindow = GetParentWindow ();
698
AdornedWindow.AllowDrop = true;
700
var e = (UIElement)AdornedWindow.Content;
702
Adorner = new ImageAdorner (e, data.ImageBackend);
704
AdornedLayer = AdornerLayer.GetAdornerLayer (e);
705
AdornedLayer.Add (Adorner);
707
AdornedWindow.DragOver += AdornedWindowOnDragOver;
710
Widget.Dispatcher.BeginInvoke ((Action)(() => {
711
var effect = DragDrop.DoDragDrop (Widget, dataObj, data.DragAction.ToWpfDropEffect ());
713
OnDragFinished (this, new DragFinishedEventArgs (effect == DragDropEffects.Move));
715
if (Adorner != null) {
716
AdornedLayer.Remove (Adorner);
720
AdornedWindow.AllowDrop = false;
721
AdornedWindow.DragOver -= AdornedWindowOnDragOver;
722
AdornedWindow = null;
727
private void AdornedWindowOnDragOver (object sender, System.Windows.DragEventArgs e)
729
WidgetDragOverHandler (sender, e);
732
public void SetDragTarget (TransferDataType [] types, DragDropAction dragAction)
734
DragDropInfo.TargetTypes = types == null ? new TransferDataType [0] : types;
735
Widget.AllowDrop = true;
738
public void SetDragSource (TransferDataType [] types, DragDropAction dragAction)
740
if (DragDropInfo.AutodetectDrag)
741
return; // Drag auto detect has been already activated.
743
DragDropInfo.AutodetectDrag = true;
744
Widget.MouseUp += WidgetMouseUpForDragHandler;
745
Widget.MouseMove += WidgetMouseMoveForDragHandler;
748
private void SetupDragRect (MouseEventArgs e)
750
var width = SystemParameters.MinimumHorizontalDragDistance;
751
var height = SystemParameters.MinimumVerticalDragDistance;
752
var loc = e.GetPosition (Widget);
753
DragDropInfo.DragRect = new Rect (loc.X - width / 2, loc.Y - height / 2, width, height);
756
void WidgetMouseUpForDragHandler (object o, EventArgs e)
758
DragDropInfo.DragRect = Rect.Empty;
761
void WidgetMouseMoveForDragHandler (object o, MouseEventArgs e)
763
if ((enabledEvents & WidgetEvent.DragStarted) == 0)
765
if (e.LeftButton != MouseButtonState.Pressed)
768
if (DragDropInfo.DragRect.IsEmpty)
771
if (DragDropInfo.DragRect.Contains (e.GetPosition (Widget)))
774
DragStartData dragData = null;
775
Toolkit.Invoke (delegate {
776
dragData = eventSink.OnDragStarted ();
779
if (dragData != null)
780
DragStart (dragData);
782
DragDropInfo.DragRect = Rect.Empty;
785
static DragDropAction DetectDragAction (DragDropKeyStates keys)
787
if ((keys & DragDropKeyStates.ControlKey) == DragDropKeyStates.ControlKey) {
788
if ((keys & DragDropKeyStates.ShiftKey) == DragDropKeyStates.ShiftKey)
789
return DragDropAction.Link;
791
return DragDropAction.Copy;
794
return DragDropAction.Move;
797
static void FillDataStore (TransferDataStore store, IDataObject data, TransferDataType [] types)
799
foreach (var type in types) {
800
string format = type.ToWpfDataFormat ();
801
if (!data.GetDataPresent (format)) {
802
// This is a workaround to support type names which don't include the assembly name.
803
// It eases integration with Windows DND.
804
format = NormalizeTypeName (format);
805
if (!data.GetDataPresent (format))
809
var value = data.GetData (format);
810
if (type == TransferDataType.Text)
811
store.AddText ((string)value);
812
else if (type == TransferDataType.Uri) {
813
var uris = ((string [])value).Select (f => new Uri (f)).ToArray ();
814
store.AddUris (uris);
815
} else if (value is byte[])
816
store.AddValue (type, (byte[]) value);
818
store.AddValue (type, value);
822
static string NormalizeTypeName (string dataType)
824
// If the string is a fully qualified type name, strip the assembly name
825
int i = dataType.IndexOf (',');
828
string asmName = dataType.Substring (i + 1).Trim ();
830
new System.Reflection.AssemblyName (asmName);
835
return dataType.Substring (0, i).Trim ();
838
protected virtual void OnDragFinished (object sender, DragFinishedEventArgs e)
840
Toolkit.Invoke (delegate {
841
this.eventSink.OnDragFinished (e);
845
protected virtual void OnDragOver (object sender, DragOverEventArgs e)
847
Toolkit.Invoke (delegate {
848
eventSink.OnDragOver (e);
852
protected virtual void OnDragLeave (object sender, EventArgs e)
854
Toolkit.Invoke (delegate {
855
eventSink.OnDragLeave (e);
859
void WidgetDragOverHandler (object sender, System.Windows.DragEventArgs e)
861
var types = e.Data.GetFormats ().Select (t => t.ToXwtTransferType ()).ToArray ();
862
var pos = e.GetPosition (Widget).ToXwtPoint ();
863
var proposedAction = DetectDragAction (e.KeyStates);
865
e.Handled = true; // Prevent default handlers from being used.
867
if (Adorner != null) {
868
var w = GetParentWindow ();
869
var v = (UIElement)w.Content;
871
if (w != AdornedWindow) {
872
AdornedLayer.Remove (Adorner);
874
AdornedWindow.AllowDrop = false;
875
AdornedWindow.DragOver -= AdornedWindowOnDragOver;
878
AdornedWindow.AllowDrop = true;
879
AdornedWindow.DragOver += AdornedWindowOnDragOver;
881
AdornedLayer = AdornerLayer.GetAdornerLayer (v);
882
AdornedLayer.Add (Adorner);
885
Adorner.Offset = e.GetPosition (v);
888
if ((enabledEvents & WidgetEvent.DragOverCheck) > 0) {
889
var checkArgs = new DragOverCheckEventArgs (pos, types, proposedAction);
890
Toolkit.Invoke (delegate {
891
eventSink.OnDragOverCheck (checkArgs);
893
if (checkArgs.AllowedAction == DragDropAction.None) {
894
e.Effects = currentDragEffect = DragDropEffects.None;
897
if (checkArgs.AllowedAction != DragDropAction.Default) {
898
e.Effects = currentDragEffect = checkArgs.AllowedAction.ToWpfDropEffect ();
903
if ((enabledEvents & WidgetEvent.DragOver) > 0) {
904
var store = new TransferDataStore ();
905
FillDataStore (store, e.Data, DragDropInfo.TargetTypes);
907
var args = new DragOverEventArgs (pos, store, proposedAction);
908
OnDragOver (sender, args);
909
if (args.AllowedAction == DragDropAction.None) {
910
e.Effects = currentDragEffect = DragDropEffects.None;
913
if (args.AllowedAction != DragDropAction.Default) {
914
e.Effects = currentDragEffect = args.AllowedAction.ToWpfDropEffect ();
919
e.Effects = currentDragEffect = proposedAction.ToWpfDropEffect ();
922
void WidgetDropHandler (object sender, System.Windows.DragEventArgs e)
924
WidgetDragLeaveHandler (sender, e);
926
var types = e.Data.GetFormats ().Select (t => t.ToXwtTransferType ()).ToArray ();
927
var pos = e.GetPosition (Widget).ToXwtPoint ();
928
var actualEffect = currentDragEffect;
930
e.Handled = true; // Prevent default handlers from being used.
931
e.Effects = DragDropEffects.None;
933
if ((enabledEvents & WidgetEvent.DragDropCheck) > 0) {
934
var checkArgs = new DragCheckEventArgs (pos, types, actualEffect.ToXwtDropAction ());
935
bool res = Toolkit.Invoke (delegate {
936
eventSink.OnDragDropCheck (checkArgs);
939
if (checkArgs.Result == DragDropResult.Canceled || !res) {
940
e.Effects = DragDropEffects.None;
945
if ((enabledEvents & WidgetEvent.DragDrop) > 0) {
946
var store = new TransferDataStore ();
947
FillDataStore (store, e.Data, DragDropInfo.TargetTypes);
949
var args = new DragEventArgs (pos, store, actualEffect.ToXwtDropAction ());
950
Toolkit.Invoke (delegate {
951
eventSink.OnDragDrop (args);
955
e.Effects = actualEffect;
959
void WidgetDragLeaveHandler (object sender, System.Windows.DragEventArgs e)
961
OnDragLeave (sender, e);
964
private void WidgetMouseEnteredHandler (object sender, MouseEventArgs e)
966
Toolkit.Invoke (eventSink.OnMouseEntered);
969
private void WidgetMouseExitedHandler (object sender, MouseEventArgs e)
971
Toolkit.Invoke (eventSink.OnMouseExited);
974
private void WidgetMouseMoveHandler (object sender, MouseEventArgs e)
976
Toolkit.Invoke (() => {
977
var p = e.GetPosition (Widget);
978
eventSink.OnMouseMoved (new MouseMovedEventArgs (
979
e.Timestamp, p.X * WidthPixelRatio, p.Y * HeightPixelRatio));
983
private int mouseScrollCumulation = 0;
985
private void WidgetMouseWheelHandler (object sender, MouseWheelEventArgs e)
987
mouseScrollCumulation += e.Delta;
988
int jumps = mouseScrollCumulation / 120;
989
mouseScrollCumulation %= 120;
990
var p = e.GetPosition(Widget);
991
Toolkit.Invoke (delegate {
992
for (int i = 0; i < jumps; i++) {
993
eventSink.OnMouseScrolled(new MouseScrolledEventArgs(
994
e.Timestamp, p.X * WidthPixelRatio, p.Y * HeightPixelRatio, ScrollDirection.Up));
996
for (int i = 0; i > jumps; i--) {
997
eventSink.OnMouseScrolled(new MouseScrolledEventArgs(
998
e.Timestamp, p.X * WidthPixelRatio, p.Y * HeightPixelRatio, ScrollDirection.Down));
1003
private void WidgetOnSizeChanged (object sender, SizeChangedEventArgs e)
1005
if (Widget.IsVisible)
1006
Toolkit.Invoke (this.eventSink.OnBoundsChanged);
1010
public interface IWpfWidgetBackend
1012
FrameworkElement Widget { get; }
1015
public interface IWpfWidget
1017
WidgetBackend Backend { get; set; }