You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
284 lines
9.8 KiB
284 lines
9.8 KiB
/*************************************************************************************
|
|
|
|
Extended WPF Toolkit
|
|
|
|
Copyright (C) 2007-2013 Xceed Software Inc.
|
|
|
|
This program is provided to you under the terms of the Microsoft Public
|
|
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|
|
|
For more features, controls, and fast professional support,
|
|
pick up the Plus Edition at http://xceed.com/wpf_toolkit
|
|
|
|
Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids
|
|
|
|
***********************************************************************************/
|
|
|
|
using System;
|
|
using System.Collections.ObjectModel;
|
|
using System.ComponentModel;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using Xceed.Wpf.Toolkit.Core.Utilities;
|
|
|
|
namespace Xceed.Wpf.Toolkit.Panels
|
|
{
|
|
public class WrapPanel : AnimationPanel
|
|
{
|
|
#region Orientation Property
|
|
|
|
public static readonly DependencyProperty OrientationProperty =
|
|
StackPanel.OrientationProperty.AddOwner( typeof( WrapPanel ),
|
|
new FrameworkPropertyMetadata( Orientation.Horizontal,
|
|
new PropertyChangedCallback( WrapPanel.OnOrientationChanged ) ) );
|
|
|
|
public Orientation Orientation
|
|
{
|
|
get
|
|
{
|
|
return _orientation;
|
|
}
|
|
set
|
|
{
|
|
base.SetValue( WrapPanel.OrientationProperty, value );
|
|
}
|
|
}
|
|
|
|
private static void OnOrientationChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
|
|
{
|
|
WrapPanel panel = ( WrapPanel )d;
|
|
panel._orientation = ( Orientation )e.NewValue;
|
|
panel.InvalidateMeasure();
|
|
}
|
|
|
|
private Orientation _orientation;
|
|
|
|
#endregion
|
|
|
|
#region ItemWidth Property
|
|
|
|
public static readonly DependencyProperty ItemWidthProperty =
|
|
DependencyProperty.Register( "ItemWidth", typeof( double ), typeof( WrapPanel ),
|
|
new FrameworkPropertyMetadata( double.NaN,
|
|
new PropertyChangedCallback( WrapPanel.OnInvalidateMeasure ) ), new ValidateValueCallback( WrapPanel.IsWidthHeightValid ) );
|
|
|
|
[TypeConverter( typeof( LengthConverter ) )]
|
|
public double ItemWidth
|
|
{
|
|
get
|
|
{
|
|
return ( double )base.GetValue( WrapPanel.ItemWidthProperty );
|
|
}
|
|
set
|
|
{
|
|
base.SetValue( WrapPanel.ItemWidthProperty, value );
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ItemHeight Property
|
|
|
|
public static readonly DependencyProperty ItemHeightProperty =
|
|
DependencyProperty.Register( "ItemHeight", typeof( double ), typeof( WrapPanel ),
|
|
new FrameworkPropertyMetadata( double.NaN,
|
|
new PropertyChangedCallback( WrapPanel.OnInvalidateMeasure ) ), new ValidateValueCallback( WrapPanel.IsWidthHeightValid ) );
|
|
|
|
[TypeConverter( typeof( LengthConverter ) )]
|
|
public double ItemHeight
|
|
{
|
|
get
|
|
{
|
|
return ( double )base.GetValue( WrapPanel.ItemHeightProperty );
|
|
}
|
|
set
|
|
{
|
|
base.SetValue( WrapPanel.ItemHeightProperty, value );
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IsChildOrderReversed Property
|
|
|
|
public static readonly DependencyProperty IsStackReversedProperty =
|
|
DependencyProperty.Register( "IsChildOrderReversed", typeof( bool ), typeof( WrapPanel ),
|
|
new FrameworkPropertyMetadata( false,
|
|
new PropertyChangedCallback( WrapPanel.OnInvalidateMeasure ) ) );
|
|
|
|
public bool IsChildOrderReversed
|
|
{
|
|
get
|
|
{
|
|
return ( bool )this.GetValue( WrapPanel.IsStackReversedProperty );
|
|
}
|
|
set
|
|
{
|
|
this.SetValue( WrapPanel.IsStackReversedProperty, value );
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
protected override Size MeasureChildrenOverride( UIElementCollection children, Size constraint )
|
|
{
|
|
double desiredExtent = 0;
|
|
double desiredStack = 0;
|
|
|
|
bool isHorizontal = ( this.Orientation == Orientation.Horizontal );
|
|
double constraintExtent = ( isHorizontal ? constraint.Width : constraint.Height );
|
|
|
|
double itemWidth = ItemWidth;
|
|
double itemHeight = ItemHeight;
|
|
double itemExtent = ( isHorizontal ? itemWidth : itemHeight );
|
|
|
|
bool hasExplicitItemWidth = !double.IsNaN( itemWidth );
|
|
bool hasExplicitItemHeight = !double.IsNaN( itemHeight );
|
|
bool useItemExtent = ( isHorizontal ? hasExplicitItemWidth : hasExplicitItemHeight );
|
|
|
|
double lineExtent = 0;
|
|
double lineStack = 0;
|
|
|
|
Size childConstraint = new Size( ( hasExplicitItemWidth ? itemWidth : constraint.Width ),
|
|
( hasExplicitItemHeight ? itemHeight : constraint.Height ) );
|
|
|
|
bool isReversed = this.IsChildOrderReversed;
|
|
int from = isReversed ? children.Count - 1 : 0;
|
|
int to = isReversed ? 0 : children.Count - 1;
|
|
int step = isReversed ? -1 : 1;
|
|
|
|
for( int i = from, pass = 0; pass < children.Count; i += step, pass++ )
|
|
{
|
|
UIElement child = children[ i ] as UIElement;
|
|
|
|
child.Measure( childConstraint );
|
|
|
|
double childExtent = isHorizontal
|
|
? ( hasExplicitItemWidth ? itemWidth : child.DesiredSize.Width )
|
|
: ( hasExplicitItemHeight ? itemHeight : child.DesiredSize.Height );
|
|
double childStack = isHorizontal
|
|
? ( hasExplicitItemHeight ? itemHeight : child.DesiredSize.Height )
|
|
: ( hasExplicitItemWidth ? itemWidth : child.DesiredSize.Width );
|
|
|
|
if( lineExtent + childExtent > constraintExtent )
|
|
{
|
|
desiredExtent = Math.Max( lineExtent, desiredExtent );
|
|
desiredStack += lineStack;
|
|
lineExtent = childExtent;
|
|
lineStack = childStack;
|
|
|
|
if( childExtent > constraintExtent )
|
|
{
|
|
desiredExtent = Math.Max( childExtent, desiredExtent );
|
|
desiredStack += childStack;
|
|
lineExtent = 0;
|
|
lineStack = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lineExtent += childExtent;
|
|
lineStack = Math.Max( childStack, lineStack );
|
|
}
|
|
}
|
|
|
|
desiredExtent = Math.Max( lineExtent, desiredExtent );
|
|
desiredStack += lineStack;
|
|
|
|
return isHorizontal
|
|
? new Size( desiredExtent, desiredStack )
|
|
: new Size( desiredStack, desiredExtent );
|
|
}
|
|
|
|
protected override Size ArrangeChildrenOverride( UIElementCollection children, Size finalSize )
|
|
{
|
|
bool isHorizontal = ( this.Orientation == Orientation.Horizontal );
|
|
double finalExtent = ( isHorizontal ? finalSize.Width : finalSize.Height );
|
|
|
|
double itemWidth = this.ItemWidth;
|
|
double itemHeight = this.ItemHeight;
|
|
double itemExtent = ( isHorizontal ? itemWidth : itemHeight );
|
|
|
|
bool hasExplicitItemWidth = !double.IsNaN( itemWidth );
|
|
bool hasExplicitItemHeight = !double.IsNaN( itemHeight );
|
|
bool useItemExtent = ( isHorizontal ? hasExplicitItemWidth : hasExplicitItemHeight );
|
|
|
|
double lineExtent = 0;
|
|
double lineStack = 0;
|
|
double lineStackSum = 0;
|
|
|
|
int from = this.IsChildOrderReversed ? children.Count - 1 : 0;
|
|
int to = this.IsChildOrderReversed ? 0 : children.Count - 1;
|
|
int step = this.IsChildOrderReversed ? -1 : 1;
|
|
|
|
Collection<UIElement> childrenInLine = new Collection<UIElement>();
|
|
|
|
for( int i = from, pass = 0; pass < children.Count; i += step, pass++ )
|
|
{
|
|
UIElement child = children[ i ] as UIElement;
|
|
|
|
double childExtent = isHorizontal
|
|
? ( hasExplicitItemWidth ? itemWidth : child.DesiredSize.Width )
|
|
: ( hasExplicitItemHeight ? itemHeight : child.DesiredSize.Height );
|
|
double childStack = isHorizontal
|
|
? ( hasExplicitItemHeight ? itemHeight : child.DesiredSize.Height )
|
|
: ( hasExplicitItemWidth ? itemWidth : child.DesiredSize.Width );
|
|
|
|
if( lineExtent + childExtent > finalExtent )
|
|
{
|
|
this.ArrangeLineOfChildren( childrenInLine, isHorizontal, lineStack, lineStackSum, itemExtent, useItemExtent );
|
|
|
|
lineStackSum += lineStack;
|
|
lineExtent = childExtent;
|
|
|
|
if( childExtent > finalExtent )
|
|
{
|
|
childrenInLine.Add( child );
|
|
this.ArrangeLineOfChildren( childrenInLine, isHorizontal, childStack, lineStackSum, itemExtent, useItemExtent );
|
|
lineStackSum += childStack;
|
|
lineExtent = 0;
|
|
}
|
|
childrenInLine.Add( child );
|
|
}
|
|
else
|
|
{
|
|
childrenInLine.Add( child );
|
|
lineExtent += childExtent;
|
|
lineStack = Math.Max( childStack, lineStack );
|
|
}
|
|
}
|
|
|
|
if( childrenInLine.Count > 0 )
|
|
{
|
|
this.ArrangeLineOfChildren( childrenInLine, isHorizontal, lineStack, lineStackSum, itemExtent, useItemExtent );
|
|
}
|
|
|
|
return finalSize;
|
|
}
|
|
|
|
private void ArrangeLineOfChildren( Collection<UIElement> children, bool isHorizontal, double lineStack, double lineStackSum, double itemExtent, bool useItemExtent )
|
|
{
|
|
double extent = 0;
|
|
foreach( UIElement child in children )
|
|
{
|
|
double childExtent = ( isHorizontal ? child.DesiredSize.Width : child.DesiredSize.Height );
|
|
double elementExtent = ( useItemExtent ? itemExtent : childExtent );
|
|
this.ArrangeChild( child, isHorizontal ? new Rect( extent, lineStackSum, elementExtent, lineStack )
|
|
: new Rect( lineStackSum, extent, lineStack, elementExtent ) );
|
|
extent += elementExtent;
|
|
}
|
|
children.Clear();
|
|
}
|
|
|
|
private static void OnInvalidateMeasure( DependencyObject d, DependencyPropertyChangedEventArgs e )
|
|
{
|
|
( ( AnimationPanel )d ).InvalidateMeasure();
|
|
}
|
|
|
|
private static bool IsWidthHeightValid( object value )
|
|
{
|
|
double num = ( double )value;
|
|
return ( DoubleHelper.IsNaN( num ) || ( ( num >= 0d ) && !double.IsPositiveInfinity( num ) ) );
|
|
}
|
|
}
|
|
}
|
|
|