5
// Eric Maupin <ermau@xamarin.com>
6
// Lluis Sanchez <lluis@xamarin.com>
8
// Copyright (c) 2012 Xamarin, Inc.
10
// Permission is hereby granted, free of charge, to any person obtaining a copy
11
// of this software and associated documentation files (the "Software"), to deal
12
// in the Software without restriction, including without limitation the rights
13
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
// copies of the Software, and to permit persons to whom the Software is
15
// furnished to do so, subject to the following conditions:
17
// The above copyright notice and this permission notice shall be included in
18
// all copies or substantial portions of the Software.
20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31
using System.Windows.Controls;
32
using System.Windows.Controls.Primitives;
35
using Orientation = Xwt.Backends.Orientation;
36
using SW = System.Windows;
37
using SWC = System.Windows.Controls;
38
using System.Collections.Generic;
40
namespace Xwt.WPFBackend
42
public class PanedBackend
43
: WidgetBackend, IPanedBackend
46
Orientation direction;
47
PanelInfo panel1 = new PanelInfo ();
48
PanelInfo panel2 = new PanelInfo ();
49
GridSplitter splitter;
50
private const int SplitterSize = 4;
51
private bool reportPositionChanged;
56
public UIElement Widget;
58
public DefinitionBase Definition;
59
public int PanelIndex;
61
public WidgetBackend Backend;
63
public bool HasWidget { get { return Widget != null; } }
65
public IWidgetSurface WidgetSurface {
66
get { return (IWidgetSurface)Backend.Frontend; }
69
public GridLength Size
73
if (Definition is ColumnDefinition)
74
return ((ColumnDefinition)Definition).Width;
76
return ((RowDefinition)Definition).Height;
80
if (Definition is ColumnDefinition)
81
((ColumnDefinition)Definition).Width = value;
83
((RowDefinition)Definition).Height = value;
88
public void Initialize (Orientation dir)
92
Grid = new PanedGrid () { Backend = this };
94
// Create all the row/column definitions and the splitter
96
if (direction == Orientation.Horizontal) {
97
ColumnDefinition definition = new ColumnDefinition ();
98
definition.Width = new GridLength (1, GridUnitType.Star);
99
Grid.ColumnDefinitions.Add (definition);
100
panel1.Definition = definition;
102
splitter = new GridSplitter {
103
ResizeDirection = GridResizeDirection.Columns,
104
VerticalAlignment = VerticalAlignment.Stretch,
105
HorizontalAlignment = HorizontalAlignment.Center,
108
Grid.ColumnDefinitions.Add (new ColumnDefinition { Width = GridLength.Auto });
109
Grid.SetColumn (splitter, 1);
110
Grid.Children.Add (splitter);
112
definition = new ColumnDefinition ();
113
definition.Width = new GridLength (1, GridUnitType.Star);
114
Grid.ColumnDefinitions.Add (definition);
115
panel2.Definition = definition;
118
RowDefinition definition = new RowDefinition ();
119
definition.Height = new GridLength (1, GridUnitType.Star);
120
Grid.RowDefinitions.Add (definition);
121
panel1.Definition = definition;
123
splitter = new GridSplitter {
124
ResizeDirection = GridResizeDirection.Rows,
125
HorizontalAlignment = HorizontalAlignment.Stretch,
126
VerticalAlignment = VerticalAlignment.Center,
127
Height = SplitterSize
129
Grid.RowDefinitions.Add (new RowDefinition { Height = GridLength.Auto });
130
Grid.SetRow (splitter, 1);
131
Grid.Children.Add (splitter);
133
definition = new RowDefinition ();
134
definition.Height = new GridLength (1, GridUnitType.Star);
135
Grid.RowDefinitions.Add (definition);
136
panel2.Definition = definition;
138
panel1.PanelIndex = 0;
139
panel2.PanelIndex = 2;
140
splitter.Visibility = Visibility.Hidden;
142
splitter.DragDelta += delegate
144
if (position != panel1.Size.Value) {
145
position = panel1.Size.Value;
146
NotifyPositionChanged ();
151
public double Position
154
return position != -1 ? position * (direction == Orientation.Horizontal ? WidthPixelRatio : HeightPixelRatio) : 0;
157
value /= direction == Orientation.Horizontal ? WidthPixelRatio : HeightPixelRatio;
158
if (position != value) {
160
NotifyPositionChanged ();
165
internal void NotifyPositionChanged ()
167
if (this.reportPositionChanged)
168
Toolkit.Invoke (((IPanedEventSink)EventSink).OnPositionChanged);
171
PanelInfo GetPanel (int panel)
173
return panel == 1 ? panel1 : panel2;
178
get { return panel1.HasWidget && panel2.HasWidget; }
181
public void SetPanel (int panel, IWidgetBackend widget, bool resize, bool shrink)
183
var panelWidget = (UIElement)widget.NativeWidget;
185
var pi = GetPanel (panel);
186
pi.Widget = panelWidget;
187
pi.Backend = (WidgetBackend)widget;
191
if (direction == Orientation.Horizontal)
192
Grid.SetColumn (pi.Widget, pi.PanelIndex);
194
Grid.SetRow (pi.Widget, pi.PanelIndex);
196
Grid.Children.Add (pi.Widget);
198
UpdateSplitterVisibility ();
201
public void UpdatePanel (int panel, bool resize, bool shrink)
203
var pi = GetPanel (panel);
206
Grid.InvalidateArrange ();
209
public void RemovePanel (int panel)
211
var pi = GetPanel (panel);
212
Grid.Children.Remove (pi.Widget);
214
UpdateSplitterVisibility ();
217
public override WidgetSize GetPreferredWidth ()
219
if (panel1.HasWidget && panel2.HasWidget) {
220
if (direction == Orientation.Horizontal) {
221
var ws = panel1.WidgetSurface.GetPreferredWidth ();
222
ws += panel2.WidgetSurface.GetPreferredWidth ();
227
var ws = panel1.WidgetSurface.GetPreferredWidth ();
228
return ws.UnionWith (panel2.WidgetSurface.GetPreferredWidth ());
231
else if (panel1.HasWidget)
232
return panel1.WidgetSurface.GetPreferredWidth ();
233
else if (panel2.HasWidget)
234
return panel2.WidgetSurface.GetPreferredWidth ();
236
return new WidgetSize (0);
239
public override WidgetSize GetPreferredHeightForWidth (double width)
241
if (panel1.HasWidget && panel2.HasWidget) {
242
var tempPos = position;
243
var availableWidth = width - SplitterSize;
244
if (direction == Orientation.Horizontal) {
245
if (!panel1.Shrink) {
246
var w1 = panel1.WidgetSurface.GetPreferredWidth ().MinSize;
250
if (!panel2.Shrink) {
251
var w2 = panel2.WidgetSurface.GetPreferredWidth ().MinSize;
252
if (availableWidth - tempPos < w2)
253
tempPos = availableWidth - w2;
255
var ws = panel1.WidgetSurface.GetPreferredHeightForWidth (tempPos);
256
ws = ws.UnionWith (panel2.WidgetSurface.GetPreferredHeightForWidth (availableWidth - tempPos));
260
var ws = panel1.WidgetSurface.GetPreferredHeightForWidth (width);
261
ws = ws.UnionWith (panel2.WidgetSurface.GetPreferredHeightForWidth (width));
266
else if (panel1.HasWidget)
267
return panel1.WidgetSurface.GetPreferredHeightForWidth (width);
268
else if (panel2.HasWidget)
269
return panel2.WidgetSurface.GetPreferredHeightForWidth (width);
271
return new WidgetSize (0);
274
public override WidgetSize GetPreferredHeight ()
276
if (panel1.HasWidget && panel2.HasWidget) {
277
if (direction == Orientation.Vertical) {
278
var ws = panel1.WidgetSurface.GetPreferredHeight ();
279
ws += panel2.WidgetSurface.GetPreferredHeight ();
284
var ws = panel1.WidgetSurface.GetPreferredHeight ();
285
return ws.UnionWith (panel2.WidgetSurface.GetPreferredHeight ());
288
else if (panel1.HasWidget)
289
return panel1.WidgetSurface.GetPreferredHeight ();
290
else if (panel2.HasWidget)
291
return panel2.WidgetSurface.GetPreferredHeight ();
293
return new WidgetSize (0);
296
public override WidgetSize GetPreferredWidthForHeight (double width)
298
if (panel1.HasWidget && panel2.HasWidget) {
299
var tempPos = position;
300
var availableWidth = width - SplitterSize;
301
if (direction == Orientation.Vertical) {
302
if (!panel1.Shrink) {
303
var w1 = panel1.WidgetSurface.GetPreferredHeight ().MinSize;
307
if (!panel2.Shrink) {
308
var w2 = panel2.WidgetSurface.GetPreferredHeight ().MinSize;
309
if (availableWidth - tempPos < w2)
310
tempPos = availableWidth - w2;
312
var ws = panel1.WidgetSurface.GetPreferredWidthForHeight (tempPos);
313
ws = ws.UnionWith (panel2.WidgetSurface.GetPreferredWidthForHeight (availableWidth - tempPos));
317
var ws = panel1.WidgetSurface.GetPreferredWidthForHeight (width);
318
ws = ws.UnionWith (panel2.WidgetSurface.GetPreferredWidthForHeight (width));
323
else if (panel1.HasWidget)
324
return panel1.WidgetSurface.GetPreferredWidthForHeight (width);
325
else if (panel2.HasWidget)
326
return panel2.WidgetSurface.GetPreferredWidthForHeight (width);
328
return new WidgetSize (0);
331
internal void ArrangeChildren (SW.Size size)
333
double newSize = direction == Orientation.Horizontal ? size.Width : size.Height;
334
double splitterDesiredSize = SplitterSize;
335
double availableSize;
337
availableSize = newSize - splitterDesiredSize;
338
if (availableSize <= 0)
341
if (panel1.Widget != null && panel2.Widget != null) {
343
// If the bounds have changed, we have to calculate a new current position
344
if (lastSize != newSize || position == -1) {
345
double oldAvailableSize = lastSize - SplitterSize;
347
position = availableSize / 2;
348
else if (IsFixed (panel2)) {
349
var oldPanel2Size = oldAvailableSize - position - SplitterSize;
350
position = availableSize - oldPanel2Size - SplitterSize;
352
else if (!IsFixed (panel1))
353
position = availableSize * (position / oldAvailableSize);
356
if (!panel1.Shrink) {
357
var w = panel1.WidgetSurface;
358
var min = direction == Orientation.Horizontal ? w.GetPreferredWidth ().MinSize: w.GetPreferredHeight ().MinSize;
362
if (!panel2.Shrink) {
363
var w = panel2.WidgetSurface;
364
var min = direction == Orientation.Horizontal ? w.GetPreferredWidth ().MinSize : w.GetPreferredHeight ().MinSize;
365
if (availableSize - position < min) {
366
position = availableSize - min;
372
if (position > availableSize)
373
position = availableSize;
375
panel1.Size = new GridLength (position, GridUnitType.Star);
376
panel2.Size = new GridLength (availableSize - position, GridUnitType.Star);
378
else if (panel1.Widget != null)
379
panel1.Size = new GridLength (1, GridUnitType.Star);
380
else if (panel2 != null)
381
panel2.Size = new GridLength (1, GridUnitType.Star);
386
bool IsFixed (PanelInfo pi)
388
return !pi.Resize && (pi == panel1 ? panel2 : panel1).Resize;
391
void UpdateSplitterVisibility ()
393
if (panel1.Widget != null && panel2.Widget != null)
394
splitter.Visibility = Visibility.Visible;
396
splitter.Visibility = Visibility.Hidden;
399
public override void EnableEvent (object eventId)
401
base.EnableEvent (eventId);
403
if (eventId is PanedEvent) {
404
switch ((PanedEvent)eventId) {
405
case PanedEvent.PositionChanged:
406
this.reportPositionChanged = true;
412
public override void DisableEvent (object eventId)
414
base.DisableEvent (eventId);
416
if (eventId is PanedEvent) {
417
switch ((PanedEvent)eventId) {
418
case PanedEvent.PositionChanged:
419
this.reportPositionChanged = false;
427
get { return (Grid) Widget; }
428
set { Widget = value; }
432
class PanedGrid: Grid, IWpfWidget
434
public WidgetBackend Backend { get; set; }
436
protected override SW.Size MeasureOverride (SW.Size constraint)
438
// HACK: Fixes invalid size measure
439
// This line is hack to fix a measuring issue with Grid. For some reason, the grid 'remembers' the constraint
440
// parameter, so if MeasureOverride is called with a constraining size, but ArrangeOverride is later called
441
// with a bigger size, the Grid still uses the constrained size when determining the size of the children
442
constraint = new SW.Size (double.PositiveInfinity, double.PositiveInfinity);
444
var s = base.MeasureOverride (constraint);
445
return Backend.MeasureOverride (constraint, s);
448
protected override System.Windows.Size ArrangeOverride (System.Windows.Size arrangeSize)
450
PanedBackend b = ((PanedBackend)Backend);
451
var oldPos = b.Position;
452
b.ArrangeChildren (arrangeSize);
453
var s = base.ArrangeOverride (arrangeSize);
454
if (oldPos != b.Position)
455
b.NotifyPositionChanged ();