~halega/+junk/sharpdevelop

« back to all changes in this revision

Viewing changes to src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/GridAdorner.cs

  • Committer: sk
  • Date: 2011-09-10 05:17:57 UTC
  • Revision ID: halega@halega.com-20110910051757-qfouz1llya9m6boy
4.1.0.7915 Release Candidate 1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
 
2
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
 
3
 
 
4
using System;
 
5
using System.Diagnostics;
 
6
using System.Globalization;
 
7
using System.Linq;
 
8
using System.Windows;
 
9
using System.Windows.Controls;
 
10
using System.Windows.Input;
 
11
using System.Windows.Media;
 
12
using ICSharpCode.WpfDesign.XamlDom;
 
13
using ICSharpCode.WpfDesign.Adorners;
 
14
 
 
15
namespace ICSharpCode.WpfDesign.Designer.Controls
 
16
{
 
17
        /// <summary>
 
18
        /// Adorner that displays the blue bar next to grids that can be used to create new rows/column.
 
19
        /// </summary>
 
20
        public class GridRailAdorner : FrameworkElement
 
21
        {
 
22
                static GridRailAdorner()
 
23
                {
 
24
                        bgBrush = new SolidColorBrush(Color.FromArgb(0x35, 0x1E, 0x90, 0xff));
 
25
                        bgBrush.Freeze();
 
26
                        
 
27
                }
 
28
                
 
29
                readonly DesignItem gridItem;
 
30
                readonly Grid grid;
 
31
                readonly AdornerPanel adornerPanel;
 
32
                readonly GridSplitterAdorner previewAdorner;
 
33
                readonly Orientation orientation;
 
34
                readonly GridUnitSelector unitSelector;
 
35
                
 
36
                static readonly SolidColorBrush bgBrush;
 
37
                
 
38
                public const double RailSize = 10;
 
39
                public const double RailDistance = 6;
 
40
                public const double SplitterWidth = 10;
 
41
 
 
42
                bool displayUnitSelector; // Indicates whether Grid UnitSeletor should be displayed.
 
43
                
 
44
                public GridRailAdorner(DesignItem gridItem, AdornerPanel adornerPanel, Orientation orientation)
 
45
                {
 
46
                        Debug.Assert(gridItem != null);
 
47
                        Debug.Assert(adornerPanel != null);
 
48
                        
 
49
                        this.gridItem = gridItem;
 
50
                        this.grid = (Grid)gridItem.Component;
 
51
                        this.adornerPanel = adornerPanel;
 
52
                        this.orientation = orientation;
 
53
                        this.displayUnitSelector=false;
 
54
                        this.unitSelector = new GridUnitSelector(this);
 
55
                        adornerPanel.Children.Add(unitSelector);
 
56
                        
 
57
                        if (orientation == Orientation.Horizontal) {
 
58
                                this.Height = RailSize;
 
59
                                previewAdorner = new GridColumnSplitterAdorner(this, gridItem, null, null);
 
60
                        } else { // vertical
 
61
                                this.Width = RailSize;
 
62
                                previewAdorner = new GridRowSplitterAdorner(this, gridItem, null, null);
 
63
                        }
 
64
                        unitSelector.Orientation = orientation;
 
65
                        previewAdorner.IsPreview = true;
 
66
                        previewAdorner.IsHitTestVisible = false;
 
67
                        unitSelector.Visibility = Visibility.Hidden;
 
68
                        
 
69
                }
 
70
                
 
71
                protected override void OnRender(DrawingContext drawingContext)
 
72
                {
 
73
                        base.OnRender(drawingContext);
 
74
                        
 
75
                        if (orientation == Orientation.Horizontal) {
 
76
                                Rect bgRect = new Rect(0, 0, grid.ActualWidth, RailSize);
 
77
                                drawingContext.DrawRectangle(bgBrush, null, bgRect);
 
78
                                
 
79
                                DesignItemProperty colCollection = gridItem.Properties["ColumnDefinitions"];
 
80
                                foreach (var colItem in colCollection.CollectionElements) {
 
81
                                        ColumnDefinition column = colItem.Component as ColumnDefinition;
 
82
                                        if (column.ActualWidth < 0) continue;
 
83
                                        GridLength len = (GridLength)column.GetValue(ColumnDefinition.WidthProperty);
 
84
                                        
 
85
                                        FormattedText text = new FormattedText(GridLengthToText(len), CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface("Sergio UI"), 10, Brushes.Black);
 
86
                                        text.TextAlignment = TextAlignment.Center;
 
87
                                        drawingContext.DrawText(text, new Point(column.Offset + column.ActualWidth / 2, 0));
 
88
                                }
 
89
                        } else {
 
90
                                Rect bgRect = new Rect(0, 0, RailSize, grid.ActualHeight);
 
91
                                drawingContext.DrawRectangle(bgBrush, null, bgRect);
 
92
                                
 
93
                                DesignItemProperty rowCollection = gridItem.Properties["RowDefinitions"];
 
94
                                foreach (var rowItem in rowCollection.CollectionElements) {
 
95
                                        RowDefinition row = rowItem.Component as RowDefinition;
 
96
                                        if (row.ActualHeight < 0) continue;
 
97
                                        GridLength len = (GridLength)row.GetValue(RowDefinition.HeightProperty);
 
98
                                        
 
99
                                        FormattedText text = new FormattedText(GridLengthToText(len), CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface("Sergio UI"), 10, Brushes.Black);
 
100
                                        text.TextAlignment = TextAlignment.Center;
 
101
                                        drawingContext.PushTransform(new RotateTransform(-90));
 
102
                                        drawingContext.DrawText(text, new Point((row.Offset + row.ActualHeight / 2)*-1, 0));
 
103
                                        drawingContext.Pop();
 
104
                                }
 
105
                        }
 
106
                }
 
107
                
 
108
                #region Handle mouse events to add a new row/column
 
109
                protected override void OnMouseEnter(MouseEventArgs e)
 
110
                {
 
111
                        base.OnMouseEnter(e);
 
112
                        this.Cursor = Cursors.Cross;
 
113
                        RelativePlacement rpUnitSelector = new RelativePlacement();
 
114
                        if (orientation == Orientation.Vertical)
 
115
                        {
 
116
                                double insertionPosition = e.GetPosition(this).Y;
 
117
                                RowDefinition current = grid.RowDefinitions
 
118
                                        .FirstOrDefault(r => insertionPosition >= r.Offset &&
 
119
                                                        insertionPosition <= (r.Offset + r.ActualHeight));
 
120
                                if (current != null)
 
121
                                {
 
122
                                        DesignItem component = this.gridItem.Services.Component.GetDesignItem(current);
 
123
                                        rpUnitSelector.XOffset = -(RailSize + RailDistance) * 2.75;
 
124
                                        rpUnitSelector.WidthOffset = RailSize + RailDistance;
 
125
                                        rpUnitSelector.WidthRelativeToContentWidth = 1;
 
126
                                        rpUnitSelector.HeightOffset = 55;
 
127
                                        rpUnitSelector.YOffset = current.Offset + current.ActualHeight / 2 - 25;
 
128
                                        unitSelector.SelectedItem = component;
 
129
                                        unitSelector.Unit = ((GridLength)component.Properties[RowDefinition.HeightProperty].ValueOnInstance).GridUnitType;
 
130
                                        displayUnitSelector = true;
 
131
                                }
 
132
                                else
 
133
                                {
 
134
                                        displayUnitSelector = false;
 
135
                                }
 
136
                        }
 
137
                        else
 
138
                        {
 
139
                                double insertionPosition = e.GetPosition(this).X;
 
140
                                ColumnDefinition current = grid.ColumnDefinitions
 
141
                                        .FirstOrDefault(r => insertionPosition >= r.Offset &&
 
142
                                                        insertionPosition <= (r.Offset + r.ActualWidth));
 
143
                                if (current != null)
 
144
                                {
 
145
                                        DesignItem component = this.gridItem.Services.Component.GetDesignItem(current);
 
146
                                        Debug.Assert(component != null);
 
147
                                        rpUnitSelector.YOffset = -(RailSize + RailDistance) * 2.20;
 
148
                                        rpUnitSelector.HeightOffset = RailSize + RailDistance;
 
149
                                        rpUnitSelector.HeightRelativeToContentHeight = 1;
 
150
                                        rpUnitSelector.WidthOffset = 75;
 
151
                                        rpUnitSelector.XOffset = current.Offset + current.ActualWidth / 2 - 35;
 
152
                                        unitSelector.SelectedItem = component;
 
153
                                        unitSelector.Unit = ((GridLength)component.Properties[ColumnDefinition.WidthProperty].ValueOnInstance).GridUnitType;
 
154
                                        displayUnitSelector = true;
 
155
                                }
 
156
                                else
 
157
                                {
 
158
                                        displayUnitSelector = false;
 
159
                                }
 
160
                        }
 
161
                        if(displayUnitSelector)
 
162
                                unitSelector.Visibility = Visibility.Visible;
 
163
                        if(!adornerPanel.Children.Contains(previewAdorner))
 
164
                                adornerPanel.Children.Add(previewAdorner);
 
165
                        
 
166
                }
 
167
                
 
168
                protected override void OnMouseMove(MouseEventArgs e)
 
169
                {
 
170
                        base.OnMouseMove(e);
 
171
                        RelativePlacement rp = new RelativePlacement();
 
172
                        RelativePlacement rpUnitSelector = new RelativePlacement();
 
173
                        if (orientation == Orientation.Vertical)
 
174
                        {
 
175
                                double insertionPosition = e.GetPosition(this).Y;
 
176
                                RowDefinition current = grid.RowDefinitions
 
177
                                        .FirstOrDefault(r => insertionPosition >= r.Offset &&
 
178
                                                        insertionPosition <= (r.Offset + r.ActualHeight));
 
179
 
 
180
                                rp.XOffset = -(RailSize + RailDistance);
 
181
                                rp.WidthOffset = RailSize + RailDistance;
 
182
                                rp.WidthRelativeToContentWidth = 1;
 
183
                                rp.HeightOffset = SplitterWidth;
 
184
                                rp.YOffset = e.GetPosition(this).Y - SplitterWidth / 2;
 
185
                                if (current != null)
 
186
                                {
 
187
                                        DesignItem component = this.gridItem.Services.Component.GetDesignItem(current);
 
188
                                        rpUnitSelector.XOffset = -(RailSize + RailDistance) * 2.75;
 
189
                                        rpUnitSelector.WidthOffset = RailSize + RailDistance;
 
190
                                        rpUnitSelector.WidthRelativeToContentWidth = 1;
 
191
                                        rpUnitSelector.HeightOffset = 55;
 
192
                                        rpUnitSelector.YOffset = current.Offset + current.ActualHeight / 2 - 25;
 
193
                                        unitSelector.SelectedItem = component;
 
194
                                        unitSelector.Unit = ((GridLength)component.Properties[RowDefinition.HeightProperty].ValueOnInstance).GridUnitType;
 
195
                                        displayUnitSelector = true;
 
196
                                }
 
197
                                else
 
198
                                {
 
199
                                        displayUnitSelector = false;
 
200
                                }
 
201
                        }
 
202
                        else
 
203
                        {
 
204
                                double insertionPosition = e.GetPosition(this).X;
 
205
                                ColumnDefinition current = grid.ColumnDefinitions
 
206
                                        .FirstOrDefault(r => insertionPosition >= r.Offset &&
 
207
                                                        insertionPosition <= (r.Offset + r.ActualWidth));
 
208
 
 
209
                                rp.YOffset = -(RailSize + RailDistance);
 
210
                                rp.HeightOffset = RailSize + RailDistance;
 
211
                                rp.HeightRelativeToContentHeight = 1;
 
212
                                rp.WidthOffset = SplitterWidth;
 
213
                                rp.XOffset = e.GetPosition(this).X - SplitterWidth / 2;
 
214
 
 
215
                                if (current != null)
 
216
                                {
 
217
                                        DesignItem component = this.gridItem.Services.Component.GetDesignItem(current);
 
218
                                        Debug.Assert(component != null);
 
219
                                        rpUnitSelector.YOffset = -(RailSize + RailDistance) * 2.20;
 
220
                                        rpUnitSelector.HeightOffset = RailSize + RailDistance;
 
221
                                        rpUnitSelector.HeightRelativeToContentHeight = 1;
 
222
                                        rpUnitSelector.WidthOffset = 75;
 
223
                                        rpUnitSelector.XOffset = current.Offset + current.ActualWidth / 2 - 35;
 
224
                                        unitSelector.SelectedItem = component;
 
225
                                        unitSelector.Unit = ((GridLength)component.Properties[ColumnDefinition.WidthProperty].ValueOnInstance).GridUnitType;
 
226
                                        displayUnitSelector = true;
 
227
                                }
 
228
                                else
 
229
                                {
 
230
                                        displayUnitSelector = false;
 
231
                                }
 
232
                        }
 
233
                        AdornerPanel.SetPlacement(previewAdorner, rp);
 
234
                        if (displayUnitSelector)
 
235
                                AdornerPanel.SetPlacement(unitSelector, rpUnitSelector);
 
236
                }
 
237
                
 
238
                protected override void OnMouseLeave(MouseEventArgs e)
 
239
                {
 
240
                        base.OnMouseLeave(e);
 
241
                        Mouse.UpdateCursor();
 
242
                        if (!unitSelector.IsMouseOver)
 
243
                        {
 
244
                                unitSelector.Visibility = Visibility.Hidden;
 
245
                                displayUnitSelector = false;
 
246
                        }
 
247
                        if(adornerPanel.Children.Contains(previewAdorner))
 
248
                                adornerPanel.Children.Remove(previewAdorner);
 
249
                }
 
250
                
 
251
                protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
 
252
                {
 
253
                        base.OnMouseLeftButtonDown(e);
 
254
                        e.Handled = true;
 
255
                        Focus();
 
256
                        adornerPanel.Children.Remove(previewAdorner);
 
257
                        if (orientation == Orientation.Vertical) {
 
258
                                double insertionPosition = e.GetPosition(this).Y;
 
259
                                DesignItemProperty rowCollection = gridItem.Properties["RowDefinitions"];
 
260
                                
 
261
                                DesignItem currentRow = null;
 
262
                                
 
263
                                using (ChangeGroup changeGroup = gridItem.OpenGroup("Split grid row")) {
 
264
                                        if (rowCollection.CollectionElements.Count == 0) {
 
265
                                                DesignItem firstRow = gridItem.Services.Component.RegisterComponentForDesigner(new RowDefinition());
 
266
                                                rowCollection.CollectionElements.Add(firstRow);
 
267
                                                grid.UpdateLayout(); // let WPF assign firstRow.ActualHeight
 
268
                                                
 
269
                                                currentRow = firstRow;
 
270
                                        } else {
 
271
                                                RowDefinition current = grid.RowDefinitions
 
272
                                                        .FirstOrDefault(r => insertionPosition >= r.Offset &&
 
273
                                                                        insertionPosition <= (r.Offset + r.ActualHeight));
 
274
                                                if (current != null)
 
275
                                                        currentRow = gridItem.Services.Component.GetDesignItem(current);
 
276
                                        }
 
277
                                        
 
278
                                        if (currentRow == null)
 
279
                                                currentRow = gridItem.Services.Component.GetDesignItem(grid.RowDefinitions.Last());
 
280
                                        
 
281
                                        unitSelector.SelectedItem = currentRow;
 
282
                                        for (int i = 0; i < grid.RowDefinitions.Count; i++) {
 
283
                                                RowDefinition row = grid.RowDefinitions[i];
 
284
                                                if (row.Offset > insertionPosition) continue;
 
285
                                                if (row.Offset + row.ActualHeight < insertionPosition) continue;
 
286
                                                
 
287
                                                // split row
 
288
                                                GridLength oldLength = (GridLength)row.GetValue(RowDefinition.HeightProperty);
 
289
                                                GridLength newLength1, newLength2;
 
290
                                                SplitLength(oldLength, insertionPosition - row.Offset, row.ActualHeight, out newLength1, out newLength2);
 
291
                                                DesignItem newRowDefinition = gridItem.Services.Component.RegisterComponentForDesigner(new RowDefinition());
 
292
                                                rowCollection.CollectionElements.Insert(i + 1, newRowDefinition);
 
293
                                                rowCollection.CollectionElements[i].Properties[RowDefinition.HeightProperty].SetValue(newLength1);
 
294
                                                newRowDefinition.Properties[RowDefinition.HeightProperty].SetValue(newLength2);
 
295
                                                grid.UpdateLayout();
 
296
                                                FixIndicesAfterSplit(i, Grid.RowProperty, Grid.RowSpanProperty,insertionPosition);
 
297
                                                grid.UpdateLayout();
 
298
                                                changeGroup.Commit();
 
299
                                                break;
 
300
                                        }
 
301
                                }
 
302
                        } else {
 
303
                                double insertionPosition = e.GetPosition(this).X;
 
304
                                DesignItemProperty columnCollection = gridItem.Properties["ColumnDefinitions"];
 
305
                                
 
306
                                DesignItem currentColumn = null;
 
307
                                
 
308
                                using (ChangeGroup changeGroup = gridItem.OpenGroup("Split grid column")) {
 
309
                                        if (columnCollection.CollectionElements.Count == 0) {
 
310
                                                DesignItem firstColumn = gridItem.Services.Component.RegisterComponentForDesigner(new ColumnDefinition());
 
311
                                                columnCollection.CollectionElements.Add(firstColumn);
 
312
                                                grid.UpdateLayout(); // let WPF assign firstColumn.ActualWidth
 
313
                                                
 
314
                                                currentColumn = firstColumn;
 
315
                                        } else {
 
316
                                                ColumnDefinition current = grid.ColumnDefinitions
 
317
                                                        .FirstOrDefault(r => insertionPosition >= r.Offset &&
 
318
                                                                        insertionPosition <= (r.Offset + r.ActualWidth));
 
319
                                                if (current != null)
 
320
                                                        currentColumn = gridItem.Services.Component.GetDesignItem(current);
 
321
                                        }
 
322
                                        
 
323
                                        if (currentColumn == null)
 
324
                                                currentColumn = gridItem.Services.Component.GetDesignItem(grid.ColumnDefinitions.Last());
 
325
                                        
 
326
                                        unitSelector.SelectedItem = currentColumn;
 
327
                                        for (int i = 0; i < grid.ColumnDefinitions.Count; i++) {
 
328
                                                ColumnDefinition column = grid.ColumnDefinitions[i];
 
329
                                                if (column.Offset > insertionPosition) continue;
 
330
                                                if (column.Offset + column.ActualWidth < insertionPosition) continue;
 
331
                                                
 
332
                                                // split column
 
333
                                                GridLength oldLength = (GridLength)column.GetValue(ColumnDefinition.WidthProperty);
 
334
                                                GridLength newLength1, newLength2;
 
335
                                                SplitLength(oldLength, insertionPosition - column.Offset, column.ActualWidth, out newLength1, out newLength2);
 
336
                                                DesignItem newColumnDefinition = gridItem.Services.Component.RegisterComponentForDesigner(new ColumnDefinition());
 
337
                                                columnCollection.CollectionElements.Insert(i + 1, newColumnDefinition);
 
338
                                                columnCollection.CollectionElements[i].Properties[ColumnDefinition.WidthProperty].SetValue(newLength1);
 
339
                                                newColumnDefinition.Properties[ColumnDefinition.WidthProperty].SetValue(newLength2);
 
340
                                                grid.UpdateLayout();
 
341
                                                FixIndicesAfterSplit(i, Grid.ColumnProperty, Grid.ColumnSpanProperty,insertionPosition);
 
342
                                                changeGroup.Commit();
 
343
                                                grid.UpdateLayout();
 
344
                                                break;
 
345
                                        }
 
346
                                }
 
347
                        }
 
348
                        InvalidateVisual();
 
349
                }
 
350
                
 
351
                private void FixIndicesAfterSplit(int splitIndex, DependencyProperty idxProperty, DependencyProperty spanProperty, double insertionPostion)
 
352
                {
 
353
                        if (orientation == Orientation.Horizontal) {
 
354
                                // increment ColSpan of all controls in the split column, increment Column of all controls in later columns:
 
355
                                foreach (DesignItem child in gridItem.Properties["Children"].CollectionElements) {
 
356
                                        Point topLeft = child.View.TranslatePoint(new Point(0, 0), grid);
 
357
                                        var margin = (Thickness) child.Properties[FrameworkElement.MarginProperty].ValueOnInstance;
 
358
                                        var start = (int) child.Properties.GetAttachedProperty(idxProperty).ValueOnInstance;
 
359
                                        var span = (int) child.Properties.GetAttachedProperty(spanProperty).ValueOnInstance;
 
360
                                        if (start <= splitIndex && splitIndex < start + span) {
 
361
                                                var width = (double) child.Properties[FrameworkElement.ActualWidthProperty].ValueOnInstance;
 
362
                                                if (insertionPostion >= topLeft.X + width) {
 
363
                                                        continue;
 
364
                                                }
 
365
                                                if (insertionPostion > topLeft.X)
 
366
                                                        child.Properties.GetAttachedProperty(spanProperty).SetValue(span + 1);
 
367
                                                else {
 
368
                                                        child.Properties.GetAttachedProperty(idxProperty).SetValue(start + 1);
 
369
                                                        margin.Left = topLeft.X - insertionPostion;
 
370
                                                        child.Properties[FrameworkElement.MarginProperty].SetValue(margin);
 
371
                                                }
 
372
                                        }
 
373
                                        else if (start > splitIndex)
 
374
                                        {
 
375
                                                child.Properties.GetAttachedProperty(idxProperty).SetValue(start + 1);
 
376
                                        }
 
377
                                }
 
378
                        }
 
379
                        else
 
380
                        {
 
381
                                foreach (DesignItem child in gridItem.Properties["Children"].CollectionElements)
 
382
                                {
 
383
                                        Point topLeft = child.View.TranslatePoint(new Point(0, 0), grid);
 
384
                                        var margin = (Thickness)child.Properties[FrameworkElement.MarginProperty].ValueOnInstance;
 
385
                                        var start = (int)child.Properties.GetAttachedProperty(idxProperty).ValueOnInstance;
 
386
                                        var span = (int)child.Properties.GetAttachedProperty(spanProperty).ValueOnInstance;
 
387
                                        if (start <= splitIndex && splitIndex < start + span)
 
388
                                        {
 
389
                                                var height = (double)child.Properties[FrameworkElement.ActualHeightProperty].ValueOnInstance;
 
390
                                                if (insertionPostion >= topLeft.Y + height)
 
391
                                                        continue;
 
392
                                                if (insertionPostion > topLeft.Y)
 
393
                                                        child.Properties.GetAttachedProperty(spanProperty).SetValue(span + 1);
 
394
                                                else {
 
395
                                                        child.Properties.GetAttachedProperty(idxProperty).SetValue(start + 1);
 
396
                                                        margin.Top=topLeft.Y-insertionPostion;
 
397
                                                        child.Properties[FrameworkElement.MarginProperty].SetValue(margin);
 
398
                                                }
 
399
                                        }
 
400
                                        else if (start > splitIndex)
 
401
                                        {
 
402
                                                child.Properties.GetAttachedProperty(idxProperty).SetValue(start + 1);
 
403
                                        }
 
404
                                }
 
405
                        }
 
406
                }
 
407
                
 
408
                static void SplitLength(GridLength oldLength, double insertionPosition, double oldActualValue,
 
409
                                        out GridLength newLength1, out GridLength newLength2)
 
410
                {
 
411
                        if (oldLength.IsAuto) {
 
412
                                oldLength = new GridLength(oldActualValue);
 
413
                        }
 
414
                        double percentage = insertionPosition / oldActualValue;
 
415
                        newLength1 = new GridLength(oldLength.Value * percentage, oldLength.GridUnitType);
 
416
                        newLength2 = new GridLength(oldLength.Value - newLength1.Value, oldLength.GridUnitType);
 
417
                }
 
418
                #endregion
 
419
                
 
420
                string GridLengthToText(GridLength len)
 
421
                {
 
422
                        switch (len.GridUnitType) {
 
423
                                case GridUnitType.Auto:
 
424
                                        return "Auto";
 
425
                                case GridUnitType.Star:
 
426
                                        return len.Value == 1 ? "*" : Math.Round(len.Value, 2) + "*";
 
427
                                case GridUnitType.Pixel:
 
428
                                        return Math.Round(len.Value, 2) + "px";
 
429
                        }
 
430
                        return string.Empty;
 
431
                }
 
432
                
 
433
                public void SetGridLengthUnit(GridUnitType unit)
 
434
                {
 
435
                        DesignItem item = unitSelector.SelectedItem;
 
436
                        grid.UpdateLayout();
 
437
                        
 
438
                        Debug.Assert(item != null);
 
439
                        
 
440
                        if (orientation == Orientation.Vertical) {
 
441
                                SetGridLengthUnit(unit, item, RowDefinition.HeightProperty);
 
442
                        } else {
 
443
                                SetGridLengthUnit(unit, item, ColumnDefinition.WidthProperty);
 
444
                        }
 
445
                        grid.UpdateLayout();
 
446
                        InvalidateVisual();
 
447
                }
 
448
                
 
449
                void SetGridLengthUnit(GridUnitType unit, DesignItem item, DependencyProperty property)
 
450
                {
 
451
                        DesignItemProperty itemProperty = item.Properties[property];
 
452
                        GridLength oldValue = (GridLength)itemProperty.ValueOnInstance;
 
453
                        GridLength value = GetNewGridLength(unit, oldValue);
 
454
                        
 
455
                        if (value != oldValue) {
 
456
                                itemProperty.SetValue(value);
 
457
                        }
 
458
                }
 
459
                
 
460
                GridLength GetNewGridLength(GridUnitType unit, GridLength oldValue)
 
461
                {
 
462
                        if (unit == GridUnitType.Auto) {
 
463
                                return GridLength.Auto;
 
464
                        }
 
465
                        return new GridLength(oldValue.Value, unit);
 
466
                }
 
467
        }
 
468
        
 
469
        public abstract class GridSplitterAdorner : Control
 
470
        {
 
471
                public static readonly DependencyProperty IsPreviewProperty
 
472
                        = DependencyProperty.Register("IsPreview", typeof(bool), typeof(GridSplitterAdorner), new PropertyMetadata(SharedInstances.BoxedFalse));
 
473
                
 
474
                protected readonly Grid grid;
 
475
                protected readonly DesignItem gridItem;
 
476
                protected readonly DesignItem firstRow, secondRow; // can also be columns
 
477
                protected readonly GridRailAdorner rail;
 
478
                
 
479
                internal GridSplitterAdorner(GridRailAdorner rail, DesignItem gridItem, DesignItem firstRow, DesignItem secondRow)
 
480
                {
 
481
                        Debug.Assert(gridItem != null);
 
482
                        this.grid = (Grid)gridItem.Component;
 
483
                        this.gridItem = gridItem;
 
484
                        this.firstRow = firstRow;
 
485
                        this.secondRow = secondRow;
 
486
                        this.rail = rail;
 
487
                }
 
488
                
 
489
                public bool IsPreview {
 
490
                        get { return (bool)GetValue(IsPreviewProperty); }
 
491
                        set { SetValue(IsPreviewProperty, SharedInstances.Box(value)); }
 
492
                }
 
493
                
 
494
                ChangeGroup activeChangeGroup;
 
495
                double mouseStartPos;
 
496
                bool mouseIsDown;
 
497
                
 
498
                protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
 
499
                {
 
500
                        e.Handled = true;
 
501
                        if (CaptureMouse()) {
 
502
                                Focus();
 
503
                                mouseStartPos = GetCoordinate(e.GetPosition(grid));
 
504
                                mouseIsDown = true;
 
505
                        }
 
506
                }
 
507
                
 
508
                protected override void OnMouseMove(MouseEventArgs e)
 
509
                {
 
510
                        if (mouseIsDown) {
 
511
                                double mousePos = GetCoordinate(e.GetPosition(grid));
 
512
                                if (activeChangeGroup == null) {
 
513
                                        if (Math.Abs(mousePos - mouseStartPos)
 
514
                                            >= GetCoordinate(new Point(SystemParameters.MinimumHorizontalDragDistance, SystemParameters.MinimumVerticalDragDistance))) {
 
515
                                                activeChangeGroup = gridItem.OpenGroup("Change grid row/column size");
 
516
                                                RememberOriginalSize();
 
517
                                        }
 
518
                                }
 
519
                                if (activeChangeGroup != null) {
 
520
                                        ChangeSize(mousePos - mouseStartPos);
 
521
                                }
 
522
                        }
 
523
                }
 
524
                
 
525
                protected GridLength original1, original2;
 
526
                protected double originalPixelSize1, originalPixelSize2;
 
527
                
 
528
                protected abstract double GetCoordinate(Point point);
 
529
                protected abstract void RememberOriginalSize();
 
530
                protected abstract DependencyProperty RowColumnSizeProperty { get; }
 
531
                
 
532
                void ChangeSize(double delta)
 
533
                {
 
534
                        // delta = difference in pixels
 
535
                        
 
536
                        if (delta < -originalPixelSize1) delta = -originalPixelSize1;
 
537
                        if (delta > originalPixelSize2) delta = originalPixelSize2;
 
538
                        
 
539
                        // replace Auto lengths with absolute lengths if necessary
 
540
                        if (original1.IsAuto) original1 = new GridLength(originalPixelSize1);
 
541
                        if (original2.IsAuto) original2 = new GridLength(originalPixelSize2);
 
542
                        
 
543
                        GridLength new1;
 
544
                        if (original1.IsStar && originalPixelSize1 > 0)
 
545
                                new1 = new GridLength(original1.Value * (originalPixelSize1 + delta) / originalPixelSize1, GridUnitType.Star);
 
546
                        else
 
547
                                new1 = new GridLength(originalPixelSize1 + delta);
 
548
                        GridLength new2;
 
549
                        if (original2.IsStar && originalPixelSize2 > 0)
 
550
                                new2 = new GridLength(original2.Value * (originalPixelSize2 - delta) / originalPixelSize2, GridUnitType.Star);
 
551
                        else
 
552
                                new2 = new GridLength(originalPixelSize2 - delta);
 
553
                        firstRow.Properties[RowColumnSizeProperty].SetValue(new1);
 
554
                        secondRow.Properties[RowColumnSizeProperty].SetValue(new2);
 
555
                        UIElement e = ((UIElement)VisualTreeHelper.GetParent(this));
 
556
                        e.InvalidateArrange();
 
557
                        rail.InvalidateVisual();
 
558
                }
 
559
                
 
560
                protected override void OnMouseUp(MouseButtonEventArgs e)
 
561
                {
 
562
                        if (activeChangeGroup != null) {
 
563
                                activeChangeGroup.Commit();
 
564
                                activeChangeGroup = null;
 
565
                        }
 
566
                        Stop();
 
567
                }
 
568
                
 
569
                protected override void OnLostMouseCapture(MouseEventArgs e)
 
570
                {
 
571
                        Stop();
 
572
                }
 
573
                
 
574
                protected override void OnKeyDown(KeyEventArgs e)
 
575
                {
 
576
                        if (e.Key == Key.Escape) {
 
577
                                e.Handled = true;
 
578
                                Stop();
 
579
                        }
 
580
                }
 
581
                
 
582
                protected void Stop()
 
583
                {
 
584
                        ReleaseMouseCapture();
 
585
                        mouseIsDown = false;
 
586
                        if (activeChangeGroup != null) {
 
587
                                activeChangeGroup.Abort();
 
588
                                activeChangeGroup = null;
 
589
                        }
 
590
                }
 
591
        }
 
592
        
 
593
        public class GridRowSplitterAdorner : GridSplitterAdorner
 
594
        {
 
595
                static GridRowSplitterAdorner()
 
596
                {
 
597
                        DefaultStyleKeyProperty.OverrideMetadata(typeof(GridRowSplitterAdorner), new FrameworkPropertyMetadata(typeof(GridRowSplitterAdorner)));
 
598
                        CursorProperty.OverrideMetadata(typeof(GridRowSplitterAdorner), new FrameworkPropertyMetadata(Cursors.SizeNS));
 
599
                }
 
600
                
 
601
                internal GridRowSplitterAdorner(GridRailAdorner rail, DesignItem gridItem, DesignItem firstRow, DesignItem secondRow)
 
602
                        : base(rail, gridItem, firstRow, secondRow)
 
603
                {
 
604
                }
 
605
                
 
606
                protected override double GetCoordinate(Point point)
 
607
                {
 
608
                        return point.Y;
 
609
                }
 
610
                
 
611
                protected override void RememberOriginalSize()
 
612
                {
 
613
                        RowDefinition r1 = (RowDefinition)firstRow.Component;
 
614
                        RowDefinition r2 = (RowDefinition)secondRow.Component;
 
615
                        original1 = (GridLength)r1.GetValue(RowDefinition.HeightProperty);
 
616
                        original2 = (GridLength)r2.GetValue(RowDefinition.HeightProperty);
 
617
                        originalPixelSize1 = r1.ActualHeight;
 
618
                        originalPixelSize2 = r2.ActualHeight;
 
619
                }
 
620
                
 
621
                protected override DependencyProperty RowColumnSizeProperty {
 
622
                        get { return RowDefinition.HeightProperty; }
 
623
                }
 
624
        }
 
625
        
 
626
        public sealed class GridColumnSplitterAdorner : GridSplitterAdorner
 
627
        {
 
628
                static GridColumnSplitterAdorner()
 
629
                {
 
630
                        DefaultStyleKeyProperty.OverrideMetadata(typeof(GridColumnSplitterAdorner), new FrameworkPropertyMetadata(typeof(GridColumnSplitterAdorner)));
 
631
                        CursorProperty.OverrideMetadata(typeof(GridColumnSplitterAdorner), new FrameworkPropertyMetadata(Cursors.SizeWE));
 
632
                }
 
633
                
 
634
                internal GridColumnSplitterAdorner(GridRailAdorner rail, DesignItem gridItem, DesignItem firstRow, DesignItem secondRow)
 
635
                        : base(rail, gridItem, firstRow, secondRow)
 
636
                {
 
637
                }
 
638
                
 
639
                protected override double GetCoordinate(Point point)
 
640
                {
 
641
                        return point.X;
 
642
                }
 
643
                
 
644
                protected override void RememberOriginalSize()
 
645
                {
 
646
                        ColumnDefinition r1 = (ColumnDefinition)firstRow.Component;
 
647
                        ColumnDefinition r2 = (ColumnDefinition)secondRow.Component;
 
648
                        original1 = (GridLength)r1.GetValue(ColumnDefinition.WidthProperty);
 
649
                        original2 = (GridLength)r2.GetValue(ColumnDefinition.WidthProperty);
 
650
                        originalPixelSize1 = r1.ActualWidth;
 
651
                        originalPixelSize2 = r2.ActualWidth;
 
652
                }
 
653
                
 
654
                protected override DependencyProperty RowColumnSizeProperty {
 
655
                        get { return ColumnDefinition.WidthProperty; }
 
656
                }
 
657
        }
 
658
}