Browse Source

Started adding ScrollViewer.

Currently works so far as to scroll an image in the Images tab of the
test app. Hiding the scrollbars is currently disabled as it requires a
layout pass to be triggered during a layout pass.  Need to work out a
way around that...
pull/4/head
Steven Kirk 12 years ago
parent
commit
1a898d83aa
  1. 2
      Perspex.Base/PerspexObject.cs
  2. 2
      Perspex.Controls/Perspex.Controls.csproj
  3. 78
      Perspex.Controls/Presenters/ScrollContentPresenter.cs
  4. 20
      Perspex.Controls/Primitives/TemplatedControl.cs
  5. 95
      Perspex.Controls/ScrollViewer.cs
  6. 5
      Perspex.SceneGraph/Vector.cs
  7. 1
      Perspex.Themes.Default/DefaultTheme.cs
  8. 1
      Perspex.Themes.Default/Perspex.Themes.Default.csproj
  9. 69
      Perspex.Themes.Default/ScrollViewerStyle.cs
  10. 14
      TestApplication/Program.cs

2
Perspex.Base/PerspexObject.cs

@ -593,7 +593,7 @@ namespace Perspex
{
Contract.Requires<NullReferenceException>(property != null);
return this.Bind((PerspexProperty)property, (IObservable<object>)source, priority);
return this.Bind((PerspexProperty)property, source.Select(x => (object)x), priority);
}
/// <summary>

2
Perspex.Controls/Perspex.Controls.csproj

@ -41,6 +41,7 @@
<Compile Include="ColumnDefinitions.cs" />
<Compile Include="ContentControl.cs" />
<Compile Include="GridSplitter.cs" />
<Compile Include="Presenters\ScrollContentPresenter.cs" />
<Compile Include="Presenters\ContentPresenter.cs" />
<Compile Include="Control.cs" />
<Compile Include="ControlExtensions.cs" />
@ -71,6 +72,7 @@
<Compile Include="RowDefinition.cs" />
<Compile Include="RowDefinitions.cs" />
<Compile Include="Primitives\SelectingItemsControl.cs" />
<Compile Include="ScrollViewer.cs" />
<Compile Include="Shapes\Path.cs" />
<Compile Include="Shapes\Rectangle.cs" />
<Compile Include="Shapes\Shape.cs" />

78
Perspex.Controls/Presenters/ScrollContentPresenter.cs

@ -0,0 +1,78 @@
// -----------------------------------------------------------------------
// <copyright file="ScrollContentPresenter.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Controls.Presenters
{
using System.Linq;
using Perspex.Layout;
public class ScrollContentPresenter : ContentPresenter
{
public static PerspexProperty<Size> ExtentProperty =
ScrollViewer.ExtentProperty.AddOwner<ScrollContentPresenter>();
public static PerspexProperty<Vector> OffsetProperty =
ScrollViewer.OffsetProperty.AddOwner<ScrollContentPresenter>();
public static PerspexProperty<Size> ViewportProperty =
ScrollViewer.ViewportProperty.AddOwner<ScrollContentPresenter>();
public ScrollContentPresenter()
{
AffectsRender(OffsetProperty);
}
public Size Extent
{
get { return this.GetValue(ExtentProperty); }
private set { this.SetValue(ExtentProperty, value); }
}
public Vector Offset
{
get { return this.GetValue(OffsetProperty); }
set { this.SetValue(OffsetProperty, value); }
}
public Size Viewport
{
get { return this.GetValue(ViewportProperty); }
private set { this.SetValue(ViewportProperty, value); }
}
protected override Size MeasureOverride(Size availableSize)
{
var content = this.Content as ILayoutable;
if (content != null)
{
content.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
var size = content.DesiredSize.Value;
this.Extent = size;
return size.Constrain(availableSize);
}
else
{
return this.Extent = new Size();
}
}
protected override Size ArrangeOverride(Size finalSize)
{
var child = this.GetVisualChildren().SingleOrDefault() as ILayoutable;
this.Viewport = finalSize;
if (child != null)
{
child.Arrange(new Rect((Point)(-this.Offset), child.DesiredSize.Value));
return finalSize;
}
return new Size();
}
}
}

20
Perspex.Controls/Primitives/TemplatedControl.cs

@ -71,6 +71,26 @@ namespace Perspex.Controls.Primitives
}
}
protected T FindTemplateChild<T>(string id) where T : Control
{
return this.GetTemplateControls().OfType<T>().FirstOrDefault(x => x.Id == id);
}
protected T GetTemplateChild<T>(string id) where T : Control
{
var result = this.FindTemplateChild<T>(id);
if (result == null)
{
throw new InvalidOperationException(string.Format(
"Could not find template child '{0}' in template for '{1}'.",
id,
this.GetType().FullName));
}
return result;
}
protected virtual void OnTemplateApplied()
{
}

95
Perspex.Controls/ScrollViewer.cs

@ -0,0 +1,95 @@
// -----------------------------------------------------------------------
// <copyright file="DefinitionBase.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
using System.Reactive.Linq;
using Perspex.Controls.Presenters;
using Perspex.Controls.Primitives;
namespace Perspex.Controls
{
public class ScrollViewer : ContentControl
{
public static PerspexProperty<Size> ExtentProperty =
PerspexProperty.Register<ScrollViewer, Size>("Extent");
public static PerspexProperty<Vector> OffsetProperty =
PerspexProperty.Register<ScrollViewer, Vector>("Offset");
public static PerspexProperty<Size> ViewportProperty =
PerspexProperty.Register<ScrollViewer, Size>("Viewport");
private ScrollContentPresenter presenter;
private ScrollBar horizontalScrollBar;
private ScrollBar verticalScrollBar;
public Size Extent
{
get { return this.GetValue(ExtentProperty); }
private set { this.SetValue(ExtentProperty, value); }
}
public Vector Offset
{
get { return this.GetValue(OffsetProperty); }
set { this.SetValue(OffsetProperty, value); }
}
public Size Viewport
{
get { return this.GetValue(ViewportProperty); }
private set { this.SetValue(ViewportProperty, value); }
}
protected override void OnTemplateApplied()
{
this.presenter = this.GetTemplateChild<ScrollContentPresenter>("presenter");
this.horizontalScrollBar = this.GetTemplateChild<ScrollBar>("horizontalScrollBar");
this.verticalScrollBar = this.GetTemplateChild<ScrollBar>("verticalScrollBar");
this[!ExtentProperty] = this.presenter[!ExtentProperty];
this[!ViewportProperty] = this.presenter[!ViewportProperty];
this.presenter[!OffsetProperty] = this[!OffsetProperty];
var extentAndViewport = Observable.CombineLatest(
this.GetObservable(ExtentProperty).StartWith(this.Extent),
this.GetObservable(ViewportProperty).StartWith(this.Viewport))
.Select(x => new { Extent = x[0], Viewport = x[1] });
//this.horizontalScrollBar.Bind(
// IsVisibleProperty,
// extentAndViewport.Select(x => x.Extent.Width > x.Viewport.Width));
this.horizontalScrollBar.Bind(
ScrollBar.MaximumProperty,
extentAndViewport.Select(x => x.Extent.Width));
this.horizontalScrollBar.Bind(
ScrollBar.ViewportSizeProperty,
extentAndViewport.Select(x => x.Viewport.Width));
//this.verticalScrollBar.Bind(
// IsVisibleProperty,
// extentAndViewport.Select(x => x.Extent.Height > x.Viewport.Height));
this.verticalScrollBar.Bind(
ScrollBar.MaximumProperty,
extentAndViewport.Select(x => x.Extent.Height));
this.verticalScrollBar.Bind(
ScrollBar.ViewportSizeProperty,
extentAndViewport.Select(x => x.Viewport.Height));
var offset = Observable.CombineLatest(
this.horizontalScrollBar.GetObservable(ScrollBar.ValueProperty),
this.verticalScrollBar.GetObservable(ScrollBar.ValueProperty))
.Select(x => new Vector(x[0], x[1]));
this.Bind(OffsetProperty, offset);
}
}
}

5
Perspex.SceneGraph/Vector.cs

@ -65,6 +65,11 @@ namespace Perspex
return new Vector(a.x - b.x, a.y - b.y);
}
public static explicit operator Point(Vector a)
{
return new Point(a.x, a.y);
}
/// <summary>
/// Returns the string representation of the point.
/// </summary>

1
Perspex.Themes.Default/DefaultTheme.cs

@ -18,6 +18,7 @@ namespace Perspex.Themes.Default
this.Add(new GridSplitterStyle());
this.Add(new ItemsControlStyle());
this.Add(new ScrollBarStyle());
this.Add(new ScrollViewerStyle());
this.Add(new TabControlStyle());
this.Add(new TabItemStyle());
this.Add(new TabStripStyle());

1
Perspex.Themes.Default/Perspex.Themes.Default.csproj

@ -66,6 +66,7 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Compile Include="ScrollViewerStyle.cs" />
<Compile Include="ScrollBarStyle.cs" />
<Compile Include="GridSplitterStyle.cs" />
<Compile Include="ButtonStyle.cs" />

69
Perspex.Themes.Default/ScrollViewerStyle.cs

@ -0,0 +1,69 @@
// -----------------------------------------------------------------------
// <copyright file="ScrollViewerStyle.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Themes.Default
{
using System.Linq;
using Perspex.Controls;
using Perspex.Controls.Presenters;
using Perspex.Controls.Primitives;
using Perspex.Media;
using Perspex.Styling;
public class ScrollViewerStyle : Styles
{
public ScrollViewerStyle()
{
this.AddRange(new[]
{
new Style(x => x.OfType<ScrollViewer>())
{
Setters = new[]
{
new Setter(ScrollViewer.TemplateProperty, ControlTemplate.Create<ScrollViewer>(this.Template)),
},
},
});
}
private Control Template(ScrollViewer control)
{
return new Grid
{
ColumnDefinitions = new ColumnDefinitions
{
new ColumnDefinition(1, GridUnitType.Star),
new ColumnDefinition(GridLength.Auto),
},
RowDefinitions = new RowDefinitions
{
new RowDefinition(1, GridUnitType.Star),
new RowDefinition(GridLength.Auto),
},
Children = new Controls
{
new ScrollContentPresenter
{
Id = "presenter",
[~ContentPresenter.ContentProperty] = control[~ScrollViewer.ContentProperty],
},
new ScrollBar
{
Id = "horizontalScrollBar",
Orientation = Orientation.Horizontal,
[Grid.RowProperty] = 1,
},
new ScrollBar
{
Id = "verticalScrollBar",
Orientation = Orientation.Vertical,
[Grid.ColumnProperty] = 1,
},
},
};
}
}
}

14
TestApplication/Program.cs

@ -116,6 +116,7 @@ namespace TestApplication
{
ButtonsTab(),
TextTab(),
ImagesTab(),
ListsTab(),
SlidersTab(),
LayoutTab(),
@ -211,14 +212,19 @@ namespace TestApplication
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
Gap = 8,
Width = 120,
Children = new Controls
{
new Image
new ScrollViewer
{
Source = new Bitmap("github_icon.png"),
Width = 200,
},
Height = 200,
Content = new Image
{
Source = new Bitmap("github_icon.png"),
Width = 400,
Height = 400,
},
}
}
},
};

Loading…
Cancel
Save