~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/xwt/Xwt.WPF/Xwt.WPFBackend/WidgetBackend.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
ļ»æ//
 
2
// WidgetBackend.cs
 
3
//
 
4
// Authors:
 
5
//       Carlos Alberto Cortez <calberto.cortez@gmail.com>
 
6
//       Eric Maupin <ermau@xamarin.com>
 
7
//
 
8
// Copyright (c) 2011 Carlos Alberto Cortez
 
9
// Copyright (c) 2012 Xamarin, Inc.
 
10
//
 
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:
 
17
//
 
18
// The above copyright notice and this permission notice shall be included in
 
19
// all copies or substantial portions of the Software.
 
20
//
 
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
 
27
// THE SOFTWARE.
 
28
 
 
29
using System;
 
30
using System.Collections.Specialized;
 
31
using System.Linq;
 
32
using System.Windows;
 
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.
 
40
 
 
41
using Xwt.Backends;
 
42
using Xwt.Engine;
 
43
using Color = Xwt.Drawing.Color;
 
44
 
 
45
namespace Xwt.WPFBackend
 
46
{
 
47
        public abstract class WidgetBackend
 
48
                : Backend, IWidgetBackend, IWpfWidgetBackend
 
49
        {
 
50
                IWidgetEventSink eventSink;
 
51
                WidgetEvent enabledEvents;
 
52
                DragDropEffects currentDragEffect;
 
53
                FrameworkElement widget;
 
54
 
 
55
                class DragDropData
 
56
                {
 
57
                        // Source
 
58
                        public bool AutodetectDrag;
 
59
                        public Rect DragRect;
 
60
                        // Target
 
61
                        public TransferDataType [] TargetTypes = new TransferDataType [0];
 
62
                }
 
63
 
 
64
                DragDropData dragDropInfo;
 
65
 
 
66
                const WidgetEvent dragDropEvents = WidgetEvent.DragDropCheck | WidgetEvent.DragDrop | WidgetEvent.DragOver | WidgetEvent.DragOverCheck;
 
67
 
 
68
                // Set to true when measuring a natural size for this widget
 
69
                bool gettingNaturalSize;
 
70
 
 
71
                // Set to true when calculating the default preferred size of the widget
 
72
                bool calculatingPreferredSize;
 
73
 
 
74
                void IWidgetBackend.Initialize (IWidgetEventSink eventSink)
 
75
                {
 
76
                        this.eventSink = eventSink;
 
77
                        Initialize ();
 
78
                }
 
79
 
 
80
                protected virtual void Initialize ()
 
81
                {
 
82
                }
 
83
                
 
84
                ~WidgetBackend ()
 
85
                {
 
86
                        Dispose (false);
 
87
                }
 
88
                
 
89
                public void Dispose ()
 
90
                {
 
91
                        GC.SuppressFinalize (this);
 
92
                        Dispose (true);
 
93
                }
 
94
                
 
95
                protected virtual void Dispose (bool disposing)
 
96
                {
 
97
                }
 
98
 
 
99
                public IWidgetEventSink EventSink {
 
100
                        get { return eventSink; }
 
101
                }
 
102
 
 
103
                public object NativeWidget {
 
104
                        get { return Widget; }
 
105
                }
 
106
 
 
107
                public new Widget Frontend {
 
108
                        get { return (Widget) base.Frontend; }
 
109
                }
 
110
 
 
111
                public FrameworkElement Widget {
 
112
                        get { return widget; }
 
113
                        set
 
114
                        {
 
115
                                widget = value;
 
116
                                if (widget is IWpfWidget)
 
117
                                        ((IWpfWidget)widget).Backend = this;
 
118
                                widget.InvalidateMeasure ();
 
119
                        }
 
120
                }
 
121
 
 
122
                Color? customBackgroundColor;
 
123
 
 
124
                public virtual Color BackgroundColor {
 
125
                        get {
 
126
                                if (customBackgroundColor.HasValue)
 
127
                                        return customBackgroundColor.Value;
 
128
 
 
129
                                return DataConverter.ToXwtColor (GetWidgetColor ());
 
130
                        }
 
131
                        set {
 
132
                                customBackgroundColor = value;
 
133
                                SetWidgetColor (value);
 
134
                        }
 
135
                }
 
136
 
 
137
                SWM.Color GetWidgetColor ()
 
138
                {
 
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;
 
147
                        }
 
148
 
 
149
                        return SystemColors.ControlColor;
 
150
                }
 
151
 
 
152
                void SetWidgetColor (Color value)
 
153
                {
 
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);
 
158
                }
 
159
 
 
160
                public bool UsingCustomBackgroundColor {
 
161
                        get { return customBackgroundColor.HasValue; }
 
162
                }
 
163
 
 
164
                public virtual object Font {
 
165
                        get { return GetWidgetFont (); }
 
166
                        set {
 
167
                                SetWidgetFont ((FontData)value);
 
168
                        }
 
169
                }
 
170
 
 
171
                FontData GetWidgetFont ()
 
172
                {
 
173
                        if (!(Widget is Control)) {
 
174
                                double size = FontBackendHandler.GetPointsFromDeviceUnits (SystemFonts.MessageFontSize);
 
175
 
 
176
                                return new FontData (SystemFonts.MessageFontFamily, size, Drawing.FontSizeUnit.Points) {
 
177
                                        Style = SystemFonts.MessageFontStyle,
 
178
                                        Weight = SystemFonts.MessageFontWeight
 
179
                                };
 
180
                        }
 
181
 
 
182
                        return FontData.FromControl ((Control)Widget);
 
183
                }
 
184
 
 
185
                void SetWidgetFont (FontData font)
 
186
                {
 
187
                        if (!(Widget is Control))
 
188
                                return;
 
189
 
 
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;
 
196
                }
 
197
 
 
198
                public bool CanGetFocus {
 
199
                        get { return Widget.Focusable; }
 
200
                        set { Widget.Focusable = value; }
 
201
                }
 
202
 
 
203
                public bool HasFocus {
 
204
                        get { return Widget.IsFocused; }
 
205
                }
 
206
 
 
207
                public void SetFocus ()
 
208
                {
 
209
                        Widget.Focus ();
 
210
                }
 
211
 
 
212
                public virtual bool Sensitive {
 
213
                        get { return Widget.IsEnabled; }
 
214
                        set { Widget.IsEnabled = value; }
 
215
                }
 
216
 
 
217
                public Size Size {
 
218
                        get { return new Size (Widget.ActualWidth, Widget.ActualHeight); }
 
219
                }
 
220
 
 
221
                public virtual bool Visible {
 
222
                        get { return Widget.Visibility == Visibility.Visible; }
 
223
                        set { Widget.Visibility = value ? Visibility.Visible : Visibility.Collapsed; }
 
224
                }
 
225
 
 
226
                public string TooltipText {
 
227
                        get { return Widget.ToolTip.ToString (); }
 
228
                        set { Widget.ToolTip = value; }
 
229
                }
 
230
 
 
231
                public static FrameworkElement GetFrameworkElement (IWidgetBackend backend)
 
232
                {
 
233
                        return backend == null ? null : (FrameworkElement)backend.NativeWidget;
 
234
                }
 
235
 
 
236
                public Point ConvertToScreenCoordinates (Point widgetCoordinates)
 
237
                {
 
238
                        double wratio = WidthPixelRatio;
 
239
                        double hratio = HeightPixelRatio;
 
240
 
 
241
                        var p = Widget.PointToScreen (new System.Windows.Point (
 
242
                                widgetCoordinates.X / wratio, widgetCoordinates.Y / hratio));
 
243
 
 
244
                        return new Point (p.X * wratio, p.Y * hratio);
 
245
                }
 
246
 
 
247
                SW.Size lastNaturalSize;
 
248
 
 
249
                void GetWidgetDesiredSize (double availableWidth, double availableHeight, out SW.Size minSize, out SW.Size naturalSize)
 
250
                {
 
251
                        // Calculates the desired size of widget.
 
252
 
 
253
                        if (!Widget.IsMeasureValid) {
 
254
                                try {
 
255
                                        calculatingPreferredSize = true;
 
256
                                        gettingNaturalSize = true;
 
257
                                        Widget.Measure (new System.Windows.Size (availableWidth, availableHeight));
 
258
                                        lastNaturalSize = Widget.DesiredSize;
 
259
                                        gettingNaturalSize = false;
 
260
 
 
261
                                        Widget.InvalidateMeasure ();
 
262
                                        Widget.Measure (new System.Windows.Size (availableWidth, availableHeight));
 
263
                                }
 
264
                                finally {
 
265
                                        calculatingPreferredSize = false;
 
266
                                        gettingNaturalSize = false;
 
267
                                }
 
268
                        }
 
269
                        minSize = Widget.DesiredSize;
 
270
                        naturalSize = lastNaturalSize;
 
271
                }
 
272
 
 
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
 
278
 
 
279
                public virtual WidgetSize GetPreferredWidth ()
 
280
                {
 
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);
 
285
                }
 
286
 
 
287
                public virtual WidgetSize GetPreferredHeight ()
 
288
                {
 
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);
 
293
                }
 
294
 
 
295
                public virtual WidgetSize GetPreferredWidthForHeight (double height)
 
296
                {
 
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);
 
301
                }
 
302
 
 
303
                public virtual WidgetSize GetPreferredHeightForWidth (double width)
 
304
                {
 
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);
 
309
                }
 
310
 
 
311
                /// <summary>
 
312
                /// A default implementation of MeasureOverride to be used by all WPF widgets
 
313
                /// </summary>
 
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)
 
318
                {
 
319
                        // Calculate the natural size, if that's what is being measured
 
320
 
 
321
                        if (gettingNaturalSize) {
 
322
                                var defNaturalSize = eventSink.GetDefaultNaturalSize ();
 
323
 
 
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;
 
326
                                if (nw == -1) {
 
327
                                        nw = defNaturalSize.Width;
 
328
                                        if (nw == 0)
 
329
                                                nw = wpfMeasure.Width;
 
330
                                        wpfMeasure.Width = nw;
 
331
                                }
 
332
                                else if (nw != -2)
 
333
                                        wpfMeasure.Width = nw;
 
334
 
 
335
                                var nh = DefaultNaturalHeight;
 
336
                                if (nh == -1) {
 
337
                                        nh = defNaturalSize.Height;
 
338
                                        if (nh == 0)
 
339
                                                nh = wpfMeasure.Height;
 
340
                                        wpfMeasure.Height = nh;
 
341
                                }
 
342
                                else if (nh != -2)
 
343
                                        wpfMeasure.Height = nh;
 
344
                        }
 
345
 
 
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)
 
349
                                return wpfMeasure;
 
350
 
 
351
                        Toolkit.Invoke (delegate
 
352
                        {
 
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;
 
359
                                        }
 
360
 
 
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;
 
365
                                        }
 
366
                                }
 
367
                                else {
 
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;
 
372
                                        }
 
373
 
 
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;
 
378
                                        }
 
379
                                }
 
380
                        });
 
381
                        return wpfMeasure;
 
382
                }
 
383
 
 
384
                /// <summary>
 
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)
 
388
                /// </summary>
 
389
                protected virtual double DefaultNaturalWidth {
 
390
                        get { return -2; }
 
391
                }
 
392
 
 
393
                /// <summary>
 
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)
 
397
                /// </summary>
 
398
                protected virtual double DefaultNaturalHeight
 
399
                {
 
400
                        get { return -2; }
 
401
                }
 
402
 
 
403
                public void SetMinSize (double width, double height)
 
404
                {
 
405
                        if (width == -1)
 
406
                                Widget.ClearValue (FrameworkElement.MinWidthProperty);
 
407
                        else
 
408
                                Widget.MinWidth = width / WidthPixelRatio;
 
409
 
 
410
                        if (height == -1)
 
411
                                Widget.ClearValue (FrameworkElement.MinHeightProperty);
 
412
                        else
 
413
                                Widget.MinHeight = height / HeightPixelRatio;
 
414
                }
 
415
 
 
416
                public void SetNaturalSize (double width, double height)
 
417
                {
 
418
                        if (width == -1)
 
419
                                Widget.ClearValue (FrameworkElement.WidthProperty);
 
420
                        else
 
421
                                Widget.Width = width / WidthPixelRatio;
 
422
 
 
423
                        if (height == -1)
 
424
                                Widget.ClearValue (FrameworkElement.HeightProperty);
 
425
                        else
 
426
                                Widget.Height = height / HeightPixelRatio;
 
427
                }
 
428
 
 
429
                public void SetCursor (CursorType cursor)
 
430
                {
 
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;
 
451
                }
 
452
                
 
453
                public virtual void UpdateLayout ()
 
454
                {
 
455
                        Xwt.Widget frontend = (Xwt.Widget)Frontend;
 
456
                        widget.Margin = new Thickness (frontend.Margin.Left, frontend.Margin.Top, frontend.Margin.Right, frontend.Margin.Bottom);
 
457
                }
 
458
 
 
459
                public override void EnableEvent (object eventId)
 
460
                {
 
461
                        if (eventId is WidgetEvent) {
 
462
                                var ev = (WidgetEvent)eventId;
 
463
                                switch (ev) {
 
464
                                        case WidgetEvent.KeyPressed:
 
465
                                                Widget.KeyDown += WidgetKeyDownHandler;
 
466
                                                break;
 
467
                                        case WidgetEvent.KeyReleased:
 
468
                                                Widget.KeyDown += WidgetKeyUpHandler;
 
469
                                                break;
 
470
                                        case WidgetEvent.ButtonPressed:
 
471
                                                Widget.MouseDown += WidgetMouseDownHandler;
 
472
                                                break;
 
473
                                        case WidgetEvent.ButtonReleased:
 
474
                                                Widget.MouseUp += WidgetMouseUpHandler;
 
475
                                                break;
 
476
                                        case WidgetEvent.GotFocus:
 
477
                                                Widget.GotFocus += WidgetGotFocusHandler;
 
478
                                                break;
 
479
                                        case WidgetEvent.LostFocus:
 
480
                                                Widget.LostFocus += WidgetLostFocusHandler;
 
481
                                                break;
 
482
                                        case WidgetEvent.MouseEntered:
 
483
                                                Widget.MouseEnter += WidgetMouseEnteredHandler;
 
484
                                                break;
 
485
                                        case WidgetEvent.MouseExited:
 
486
                                                Widget.MouseLeave += WidgetMouseExitedHandler;
 
487
                                                break;
 
488
                                        case WidgetEvent.MouseMoved:
 
489
                                                Widget.MouseMove += WidgetMouseMoveHandler;
 
490
                                                break;
 
491
                                        case WidgetEvent.BoundsChanged:
 
492
                                                Widget.SizeChanged += WidgetOnSizeChanged;
 
493
                                                break;
 
494
                                        case WidgetEvent.MouseScrolled:
 
495
                                                Widget.MouseWheel += WidgetMouseWheelHandler;
 
496
                                                break;
 
497
                                }
 
498
 
 
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;
 
504
                                }
 
505
 
 
506
                                enabledEvents |= ev;
 
507
                        }
 
508
                }
 
509
 
 
510
                public override void DisableEvent (object eventId)
 
511
                {
 
512
                        if (eventId is WidgetEvent) {
 
513
                                var ev = (WidgetEvent)eventId;
 
514
                                switch (ev) {
 
515
                                        case WidgetEvent.KeyPressed:
 
516
                                                Widget.KeyDown -= WidgetKeyDownHandler;
 
517
                                                break;
 
518
                                        case WidgetEvent.KeyReleased:
 
519
                                                Widget.KeyUp -= WidgetKeyUpHandler;
 
520
                                                break;
 
521
                                        case WidgetEvent.ButtonPressed:
 
522
                                                Widget.MouseDown -= WidgetMouseDownHandler;
 
523
                                                break;
 
524
                                        case WidgetEvent.ButtonReleased:
 
525
                                                Widget.MouseUp -= WidgetMouseUpHandler;
 
526
                                                break;
 
527
                                        case WidgetEvent.MouseEntered:
 
528
                                                Widget.MouseEnter -= WidgetMouseEnteredHandler;
 
529
                                                break;
 
530
                                        case WidgetEvent.MouseExited:
 
531
                                                Widget.MouseLeave -= WidgetMouseExitedHandler;
 
532
                                                break;
 
533
                                        case WidgetEvent.MouseMoved:
 
534
                                                Widget.MouseMove -= WidgetMouseMoveHandler;
 
535
                                                break;
 
536
                                        case WidgetEvent.BoundsChanged:
 
537
                                                Widget.SizeChanged -= WidgetOnSizeChanged;
 
538
                                                break;
 
539
                                        case WidgetEvent.MouseScrolled:
 
540
                                                Widget.MouseWheel -= WidgetMouseWheelHandler;
 
541
                                                break;
 
542
                                }
 
543
 
 
544
                                enabledEvents &= ~ev;
 
545
 
 
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;
 
551
                                }
 
552
                        }
 
553
                }
 
554
 
 
555
                protected double WidthPixelRatio
 
556
                {
 
557
                        get
 
558
                        {
 
559
                                PresentationSource source = PresentationSource.FromVisual (Widget);
 
560
                                if (source == null)
 
561
                                        return 1;
 
562
 
 
563
                                Matrix m = source.CompositionTarget.TransformToDevice;
 
564
                                return m.M11;
 
565
                        }
 
566
                }
 
567
 
 
568
                protected double HeightPixelRatio
 
569
                {
 
570
                        get
 
571
                        {
 
572
                                PresentationSource source = PresentationSource.FromVisual (Widget);
 
573
                                if (source == null)
 
574
                                        return 1;
 
575
 
 
576
                                Matrix m = source.CompositionTarget.TransformToDevice;
 
577
                                return m.M22;
 
578
                        }
 
579
                }
 
580
 
 
581
                protected double DPI
 
582
                {
 
583
                        get { return WidthPixelRatio * 96; }
 
584
                }
 
585
 
 
586
                void WidgetKeyDownHandler (object sender, System.Windows.Input.KeyEventArgs e)
 
587
                {
 
588
                        KeyEventArgs args;
 
589
                        if (MapToXwtKeyArgs (e, out args)) {
 
590
                                Toolkit.Invoke (delegate {
 
591
                                        eventSink.OnKeyPressed (args);
 
592
                                });
 
593
                                if (args.Handled)
 
594
                                        e.Handled = true;
 
595
                        }
 
596
                }
 
597
 
 
598
                void WidgetKeyUpHandler (object sender, System.Windows.Input.KeyEventArgs e)
 
599
                {
 
600
                        KeyEventArgs args;
 
601
                        if (MapToXwtKeyArgs (e, out args)) {
 
602
                                Toolkit.Invoke (delegate {
 
603
                                        eventSink.OnKeyReleased (args);
 
604
                                });
 
605
                                if (args.Handled)
 
606
                                        e.Handled = true;
 
607
                        }
 
608
                }
 
609
 
 
610
                bool MapToXwtKeyArgs (System.Windows.Input.KeyEventArgs e, out KeyEventArgs result)
 
611
                {
 
612
                        result = null;
 
613
 
 
614
                        var key = KeyboardUtil.TranslateToXwtKey (e.Key);
 
615
                        if ((int)key == 0)
 
616
                                return false;
 
617
 
 
618
                        result = new KeyEventArgs (key, KeyboardUtil.GetModifiers (), e.IsRepeat, e.Timestamp);
 
619
                        return true;
 
620
                }
 
621
 
 
622
                void WidgetMouseDownHandler (object o, MouseButtonEventArgs e)
 
623
                {
 
624
                        var args = ToXwtButtonArgs (e);
 
625
                        Toolkit.Invoke (delegate () {
 
626
                                eventSink.OnButtonPressed (args);
 
627
                        });
 
628
                        if (args.Handled)
 
629
                                e.Handled = true;
 
630
                }
 
631
 
 
632
                void WidgetMouseUpHandler (object o, MouseButtonEventArgs e)
 
633
                {
 
634
                        var args = ToXwtButtonArgs (e);
 
635
                        Toolkit.Invoke (delegate () {
 
636
                                eventSink.OnButtonReleased (args);
 
637
                        });
 
638
                        if (args.Handled)
 
639
                                e.Handled = true;
 
640
                }
 
641
 
 
642
                ButtonEventArgs ToXwtButtonArgs (MouseButtonEventArgs e)
 
643
                {
 
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 ()
 
650
                        };
 
651
                }
 
652
 
 
653
                void WidgetGotFocusHandler (object o, RoutedEventArgs e)
 
654
                {
 
655
                        Toolkit.Invoke (this.eventSink.OnGotFocus);
 
656
                }
 
657
 
 
658
                void WidgetLostFocusHandler (object o, RoutedEventArgs e)
 
659
                {
 
660
                        Toolkit.Invoke (eventSink.OnLostFocus);
 
661
                }
 
662
 
 
663
                DragDropData DragDropInfo {
 
664
                        get {
 
665
                                if (dragDropInfo == null)
 
666
                                        dragDropInfo = new DragDropData ();
 
667
 
 
668
                                return dragDropInfo;
 
669
                        }
 
670
                }
 
671
 
 
672
                private static ImageAdorner Adorner;
 
673
                private static AdornerLayer AdornedLayer;
 
674
                private static System.Windows.Window AdornedWindow;
 
675
 
 
676
                private SW.Window GetParentWindow()
 
677
                {
 
678
                        FrameworkElement current = Widget;
 
679
                        while (current != null) {
 
680
                                if (current is SW.Window)
 
681
                                        return (SW.Window)current;
 
682
 
 
683
                                current = VisualTreeHelper.GetParent (current) as FrameworkElement;
 
684
                        }
 
685
 
 
686
                        return null;
 
687
                }
 
688
 
 
689
                public void DragStart (DragStartData data)
 
690
                {
 
691
                        if (data.Data == null)
 
692
                                throw new ArgumentNullException ("data");
 
693
                        
 
694
                        DataObject dataObj = data.Data.ToDataObject();
 
695
 
 
696
                        if (data.ImageBackend != null) {
 
697
                                AdornedWindow = GetParentWindow ();
 
698
                                AdornedWindow.AllowDrop = true;
 
699
 
 
700
                                var e = (UIElement)AdornedWindow.Content;
 
701
 
 
702
                                Adorner = new ImageAdorner (e, data.ImageBackend);
 
703
 
 
704
                                AdornedLayer = AdornerLayer.GetAdornerLayer (e);
 
705
                                AdornedLayer.Add (Adorner);
 
706
 
 
707
                                AdornedWindow.DragOver += AdornedWindowOnDragOver;
 
708
                        }
 
709
 
 
710
                        Widget.Dispatcher.BeginInvoke ((Action)(() => {
 
711
                                var effect = DragDrop.DoDragDrop (Widget, dataObj, data.DragAction.ToWpfDropEffect ());
 
712
 
 
713
                                OnDragFinished (this, new DragFinishedEventArgs (effect == DragDropEffects.Move));
 
714
 
 
715
                                if (Adorner != null) {
 
716
                                        AdornedLayer.Remove (Adorner);
 
717
                                        AdornedLayer = null;
 
718
                                        Adorner = null;
 
719
 
 
720
                                        AdornedWindow.AllowDrop = false;
 
721
                                        AdornedWindow.DragOver -= AdornedWindowOnDragOver;
 
722
                                        AdornedWindow = null;
 
723
                                }
 
724
                        }));
 
725
                }
 
726
 
 
727
                private void AdornedWindowOnDragOver (object sender, System.Windows.DragEventArgs e)
 
728
                {
 
729
                        WidgetDragOverHandler (sender, e);
 
730
                }
 
731
 
 
732
                public void SetDragTarget (TransferDataType [] types, DragDropAction dragAction)
 
733
                {
 
734
                        DragDropInfo.TargetTypes = types == null ? new TransferDataType [0] : types;
 
735
                        Widget.AllowDrop = true;
 
736
                }
 
737
 
 
738
                public void SetDragSource (TransferDataType [] types, DragDropAction dragAction)
 
739
                {
 
740
                        if (DragDropInfo.AutodetectDrag)
 
741
                                return; // Drag auto detect has been already activated.
 
742
 
 
743
                        DragDropInfo.AutodetectDrag = true;
 
744
                        Widget.MouseUp += WidgetMouseUpForDragHandler;
 
745
                        Widget.MouseMove += WidgetMouseMoveForDragHandler;
 
746
                }
 
747
 
 
748
                private void SetupDragRect (MouseEventArgs e)
 
749
                {
 
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);
 
754
                }
 
755
 
 
756
                void WidgetMouseUpForDragHandler (object o, EventArgs e)
 
757
                {
 
758
                        DragDropInfo.DragRect = Rect.Empty;
 
759
                }
 
760
 
 
761
                void WidgetMouseMoveForDragHandler (object o, MouseEventArgs e)
 
762
                {
 
763
                        if ((enabledEvents & WidgetEvent.DragStarted) == 0)
 
764
                                return;
 
765
                        if (e.LeftButton != MouseButtonState.Pressed)
 
766
                                return;
 
767
 
 
768
                        if (DragDropInfo.DragRect.IsEmpty)
 
769
                                SetupDragRect (e);
 
770
 
 
771
                        if (DragDropInfo.DragRect.Contains (e.GetPosition (Widget)))
 
772
                                return;
 
773
 
 
774
                        DragStartData dragData = null;
 
775
                        Toolkit.Invoke (delegate {
 
776
                                dragData = eventSink.OnDragStarted ();
 
777
                        });
 
778
 
 
779
                        if (dragData != null)
 
780
                                DragStart (dragData);
 
781
 
 
782
                        DragDropInfo.DragRect = Rect.Empty;
 
783
                }
 
784
 
 
785
                static DragDropAction DetectDragAction (DragDropKeyStates keys)
 
786
                {
 
787
                        if ((keys & DragDropKeyStates.ControlKey) == DragDropKeyStates.ControlKey) {
 
788
                                if ((keys & DragDropKeyStates.ShiftKey) == DragDropKeyStates.ShiftKey)
 
789
                                        return DragDropAction.Link;
 
790
                                else
 
791
                                        return DragDropAction.Copy;
 
792
                        }
 
793
 
 
794
                        return DragDropAction.Move;
 
795
                }
 
796
 
 
797
                static void FillDataStore (TransferDataStore store, IDataObject data, TransferDataType [] types)
 
798
                {
 
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))
 
806
                                                continue;
 
807
                                }
 
808
 
 
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);
 
817
                                else
 
818
                                        store.AddValue (type, value);
 
819
                        }
 
820
                }
 
821
 
 
822
                static string NormalizeTypeName (string dataType)
 
823
                {
 
824
                        // If the string is a fully qualified type name, strip the assembly name
 
825
                        int i = dataType.IndexOf (',');
 
826
                        if (i == -1)
 
827
                                return dataType;
 
828
                        string asmName = dataType.Substring (i + 1).Trim ();
 
829
                        try {
 
830
                                new System.Reflection.AssemblyName (asmName);
 
831
                        }
 
832
                        catch {
 
833
                                return dataType;
 
834
                        }
 
835
                        return dataType.Substring (0, i).Trim ();
 
836
                }
 
837
 
 
838
                protected virtual void OnDragFinished (object sender, DragFinishedEventArgs e)
 
839
                {
 
840
                        Toolkit.Invoke (delegate {
 
841
                                this.eventSink.OnDragFinished (e);
 
842
                        });
 
843
                }
 
844
 
 
845
                protected virtual void OnDragOver (object sender, DragOverEventArgs e)
 
846
                {
 
847
                        Toolkit.Invoke (delegate {
 
848
                                eventSink.OnDragOver (e);
 
849
                        });
 
850
                }
 
851
 
 
852
                protected virtual void OnDragLeave (object sender, EventArgs e)
 
853
                {
 
854
                        Toolkit.Invoke (delegate {
 
855
                                eventSink.OnDragLeave (e);
 
856
                        });
 
857
                }
 
858
 
 
859
                void WidgetDragOverHandler (object sender, System.Windows.DragEventArgs e)
 
860
                {
 
861
                        var types = e.Data.GetFormats ().Select (t => t.ToXwtTransferType ()).ToArray ();
 
862
                        var pos = e.GetPosition (Widget).ToXwtPoint ();
 
863
                        var proposedAction = DetectDragAction (e.KeyStates);
 
864
 
 
865
                        e.Handled = true; // Prevent default handlers from being used.
 
866
 
 
867
                        if (Adorner != null) {
 
868
                                var w = GetParentWindow ();
 
869
                                var v = (UIElement)w.Content;
 
870
 
 
871
                                if (w != AdornedWindow) {
 
872
                                        AdornedLayer.Remove (Adorner);
 
873
 
 
874
                                        AdornedWindow.AllowDrop = false;
 
875
                                        AdornedWindow.DragOver -= AdornedWindowOnDragOver;
 
876
 
 
877
                                        AdornedWindow = w;
 
878
                                        AdornedWindow.AllowDrop = true;
 
879
                                        AdornedWindow.DragOver += AdornedWindowOnDragOver;
 
880
 
 
881
                                        AdornedLayer = AdornerLayer.GetAdornerLayer (v);
 
882
                                        AdornedLayer.Add (Adorner);
 
883
                                }
 
884
 
 
885
                                Adorner.Offset = e.GetPosition (v);
 
886
                        }
 
887
 
 
888
                        if ((enabledEvents & WidgetEvent.DragOverCheck) > 0) {
 
889
                                var checkArgs = new DragOverCheckEventArgs (pos, types, proposedAction);
 
890
                                Toolkit.Invoke (delegate {
 
891
                                        eventSink.OnDragOverCheck (checkArgs);
 
892
                                });
 
893
                                if (checkArgs.AllowedAction == DragDropAction.None) {
 
894
                                        e.Effects = currentDragEffect = DragDropEffects.None;
 
895
                                        return;
 
896
                                }
 
897
                                if (checkArgs.AllowedAction != DragDropAction.Default) {
 
898
                                        e.Effects = currentDragEffect = checkArgs.AllowedAction.ToWpfDropEffect ();
 
899
                                        return;
 
900
                                }
 
901
                        }
 
902
 
 
903
                        if ((enabledEvents & WidgetEvent.DragOver) > 0) {
 
904
                                var store = new TransferDataStore ();
 
905
                                FillDataStore (store, e.Data, DragDropInfo.TargetTypes);
 
906
 
 
907
                                var args = new DragOverEventArgs (pos, store, proposedAction);
 
908
                                OnDragOver (sender, args);
 
909
                                if (args.AllowedAction == DragDropAction.None) {
 
910
                                        e.Effects = currentDragEffect = DragDropEffects.None;
 
911
                                        return;
 
912
                                }
 
913
                                if (args.AllowedAction != DragDropAction.Default) {
 
914
                                        e.Effects = currentDragEffect = args.AllowedAction.ToWpfDropEffect ();
 
915
                                        return;
 
916
                                }
 
917
                        }
 
918
 
 
919
                        e.Effects = currentDragEffect = proposedAction.ToWpfDropEffect ();
 
920
                }
 
921
 
 
922
                void WidgetDropHandler (object sender, System.Windows.DragEventArgs e)
 
923
                {
 
924
                        WidgetDragLeaveHandler (sender, e);
 
925
 
 
926
                        var types = e.Data.GetFormats ().Select (t => t.ToXwtTransferType ()).ToArray ();
 
927
                        var pos = e.GetPosition (Widget).ToXwtPoint ();
 
928
                        var actualEffect = currentDragEffect;
 
929
 
 
930
                        e.Handled = true; // Prevent default handlers from being used.
 
931
                        e.Effects = DragDropEffects.None;
 
932
 
 
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);
 
937
                                });
 
938
 
 
939
                                if (checkArgs.Result == DragDropResult.Canceled || !res) {
 
940
                                        e.Effects = DragDropEffects.None;
 
941
                                        return;
 
942
                                }
 
943
                        }
 
944
 
 
945
                        if ((enabledEvents & WidgetEvent.DragDrop) > 0) {
 
946
                                var store = new TransferDataStore ();
 
947
                                FillDataStore (store, e.Data, DragDropInfo.TargetTypes);
 
948
 
 
949
                                var args = new DragEventArgs (pos, store, actualEffect.ToXwtDropAction ());
 
950
                                Toolkit.Invoke (delegate {
 
951
                                        eventSink.OnDragDrop (args);
 
952
                                });
 
953
 
 
954
                                if (args.Success)
 
955
                                        e.Effects = actualEffect;
 
956
                        }
 
957
                }
 
958
 
 
959
                void WidgetDragLeaveHandler (object sender, System.Windows.DragEventArgs e)
 
960
                {
 
961
                        OnDragLeave (sender, e);
 
962
                }
 
963
 
 
964
                private void WidgetMouseEnteredHandler (object sender, MouseEventArgs e)
 
965
                {
 
966
                        Toolkit.Invoke (eventSink.OnMouseEntered);
 
967
                }
 
968
 
 
969
                private void WidgetMouseExitedHandler (object sender, MouseEventArgs e)
 
970
                {
 
971
                        Toolkit.Invoke (eventSink.OnMouseExited);
 
972
                }
 
973
 
 
974
                private void WidgetMouseMoveHandler (object sender, MouseEventArgs e)
 
975
                {
 
976
                        Toolkit.Invoke (() => {
 
977
                                var p = e.GetPosition (Widget);
 
978
                                eventSink.OnMouseMoved (new MouseMovedEventArgs (
 
979
                                        e.Timestamp, p.X * WidthPixelRatio, p.Y * HeightPixelRatio));
 
980
                        });
 
981
                }
 
982
 
 
983
                private int mouseScrollCumulation = 0;
 
984
 
 
985
                private void WidgetMouseWheelHandler (object sender, MouseWheelEventArgs e)
 
986
                {
 
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));
 
995
                                }
 
996
                                for (int i = 0; i > jumps; i--) {
 
997
                                        eventSink.OnMouseScrolled(new MouseScrolledEventArgs(
 
998
                                                e.Timestamp, p.X * WidthPixelRatio, p.Y * HeightPixelRatio, ScrollDirection.Down));
 
999
                                }
 
1000
                        });
 
1001
                }
 
1002
 
 
1003
                private void WidgetOnSizeChanged (object sender, SizeChangedEventArgs e)
 
1004
                {
 
1005
                        if (Widget.IsVisible)
 
1006
                                Toolkit.Invoke (this.eventSink.OnBoundsChanged);
 
1007
                }
 
1008
        }
 
1009
 
 
1010
        public interface IWpfWidgetBackend
 
1011
        {
 
1012
                FrameworkElement Widget { get; }
 
1013
        }
 
1014
 
 
1015
        public interface IWpfWidget
 
1016
        {
 
1017
                WidgetBackend Backend { get; set; }
 
1018
        }
 
1019
}