4 using System.Collections.Generic;
5 using System.Collections.Specialized;
6 using System.Diagnostics;
8 using SiliconStudio.Core.Collections;
9 using SiliconStudio.Core.Diagnostics;
10 using SiliconStudio.Core.Mathematics;
12 namespace SiliconStudio.
Paradox.UI.Panels
17 [DebuggerDisplay(
"Grid - Name={Name}")]
20 private readonly
Logger logger = GlobalLogger.GetLogger(
"UI");
32 private readonly List<List<UIElement>>[] stripIndexToNoStarElements =
34 new List<List<UIElement>>(),
35 new List<List<UIElement>>(),
36 new List<List<UIElement>>()
42 private readonly Dictionary<UIElement, List<StripDefinition>>[] elementToStripDefinitions =
44 new Dictionary<UIElement, List<StripDefinition>>(),
45 new Dictionary<
UIElement, List<StripDefinition>>(),
46 new Dictionary<UIElement, List<StripDefinition>>()
52 private readonly Dictionary<UIElement, List<StripDefinition>>[] partialStarElementToStripDefinitions =
54 new Dictionary<UIElement, List<StripDefinition>>(),
55 new Dictionary<
UIElement, List<StripDefinition>>(),
56 new Dictionary<UIElement, List<StripDefinition>>()
62 private readonly List<float>[] cachedStripIndexToStripPosition =
73 private readonly List<StripDefinition>[] dimToStarDefinitions =
75 new List<StripDefinition>(),
76 new List<StripDefinition>(),
77 new List<StripDefinition>()
83 private readonly List<StripDefinition> starDefinitionsCopy =
new List<StripDefinition>();
89 private readonly List<StripDefinition> minSortedStarDefinitions =
new List<StripDefinition>();
95 private readonly List<StripDefinition> maxSortedStarDefinitions =
new List<StripDefinition>();
101 private readonly List<StripDefinition> maxBoundedStarDefinitions =
new List<StripDefinition>();
107 private readonly List<StripDefinition> minBoundedStarDefinitions =
new List<StripDefinition>();
112 private readonly HashSet<UIElement> autoDefinedElements =
new HashSet<UIElement>();
114 private readonly
IComparer<StripDefinition> sortByIncreasingMaximumComparer =
new StripDefinition.SortByIncreasingStarRelativeMaximumValues();
115 private readonly
IComparer<StripDefinition> sortByIncreasingMinimumComparer =
new StripDefinition.SortByIncreasingStarRelativeMinimumValues();
119 foreach (var definitionCollection
in stripDefinitions)
120 definitionCollection.CollectionChanged += DefinitionCollectionChanged;
128 case NotifyCollectionChangedAction.Add:
129 modifiedElement.DefinitionChanged += OnStripDefinitionChanged;
131 case NotifyCollectionChangedAction.Remove:
132 modifiedElement.DefinitionChanged -= OnStripDefinitionChanged;
135 throw new NotImplementedException();
140 private void OnStripDefinitionChanged(
object sender,
EventArgs eventArgs)
149 public StripDefinitionCollection ColumnDefinitions
151 get {
return stripDefinitions[0]; }
160 get {
return stripDefinitions[1]; }
169 get {
return stripDefinitions[2]; }
184 CheckChildrenPositionsAndAdjustGridSize();
187 RebuildMeasureCacheData();
206 foreach (var definitions
in stripDefinitions)
207 InitializeStripDefinitionActualSize(definitions);
210 var autoElementAvailableSize = availableSizeWithoutMargins;
211 for (var dim = 0; dim < 3; dim++)
213 foreach (var definition
in stripDefinitions[dim])
215 autoElementAvailableSize[dim] -= definition.Type == StripType.Fixed ? definition.ActualSize : definition.MinimumSize;
220 foreach (var child
in autoDefinedElements)
222 var childAvailableSize = Vector3.Zero;
223 for (var dim = 0; dim < 3; dim++)
225 var autoAvailableWithMin = autoElementAvailableSize[dim];
226 foreach (var definition
in elementToStripDefinitions[dim][child])
228 autoAvailableWithMin += definition.Type == StripType.Fixed ? definition.ActualSize: definition.MinimumSize;
230 childAvailableSize[dim] += definition.ClampSizeByMinimumMaximum(definition.SizeValue);
232 childAvailableSize[dim] = Math.Min(autoAvailableWithMin, childAvailableSize[dim] + definition.MaximumSize);
235 child.Measure(childAvailableSize);
264 for (var dim = 0; dim < 3; dim++)
266 var definitions = stripDefinitions[dim];
269 InitializeStripDefinitionActualSize(definitions);
271 for (var index = 0; index < stripDefinitions[dim].Count; index++)
273 var currentDefinition = stripDefinitions[dim][index];
274 if (currentDefinition.Type !=
StripType.Auto)
278 foreach (var element
in stripIndexToNoStarElements[dim][index])
280 var currentDefinitionIndex = 0;
283 var spaceAvailable = 0f;
284 for (var i = 0; i < elementToStripDefinitions[dim][element].Count; i++)
286 spaceAvailable += elementToStripDefinitions[dim][element][i].ActualSize;
288 if (elementToStripDefinitions[dim][element][i] == currentDefinition)
289 currentDefinitionIndex = i;
291 var spaceNeeded = Math.Max(0, element.DesiredSizeWithMargins[dim] - spaceAvailable);
294 if (spaceNeeded <= 0)
298 for (var i = currentDefinitionIndex + 1; i < elementToStripDefinitions[dim][element].Count; i++)
300 var def = elementToStripDefinitions[dim][element][i];
303 spaceNeeded = Math.Max(0, spaceNeeded - (def.MaximumSize - def.ActualSize));
305 if (spaceNeeded <= 0)
309 currentDefinition.ActualSize = currentDefinition.ClampSizeByMinimumMaximum(currentDefinition.ActualSize + spaceNeeded);
315 CalculateStarStripSize(availableSizeWithoutMargins);
318 foreach (var child
in VisualChildrenCollection)
320 var availableToChildWithMargin = Vector3.Zero;
321 for (var dim = 0; dim < 3; dim++)
322 availableToChildWithMargin[dim] = SumStripCurrentSize(elementToStripDefinitions[dim][child]);
324 child.Measure(availableToChildWithMargin);
335 var neededSize = Vector3.Zero;
336 for (var dim = 0; dim < 3; dim++)
338 var definitions = stripDefinitions[dim];
342 var oneStarSize = 0f;
343 foreach (var element
in partialStarElementToStripDefinitions[dim].
Keys)
345 var elementDefinitions = partialStarElementToStripDefinitions[dim][element];
348 minSortedStarDefinitions.Clear();
349 maxSortedStarDefinitions.Clear();
352 var availableSpace = 0f;
353 foreach (var def
in elementDefinitions)
357 def.ActualSize = def.MinimumSize;
358 minSortedStarDefinitions.Add(def);
360 availableSpace += def.ActualSize;
362 var currentNeededSpace = Math.Max(0, element.DesiredSizeWithMargins[dim] - availableSpace);
365 minSortedStarDefinitions.Sort(sortByIncreasingMinimumComparer);
370 var neededOneStarSize = 0f;
371 for (var minIndex = 0; minIndex < minSortedStarDefinitions.Count && currentNeededSpace > 0; ++minIndex)
373 var minDefinition = minSortedStarDefinitions[minIndex];
375 maxSortedStarDefinitions.Add(minDefinition);
376 maxSortedStarDefinitions.Sort(sortByIncreasingMaximumComparer);
378 var nextDefinitionRelativeMinSize = (minIndex == minSortedStarDefinitions.Count - 1) ?
float.PositiveInfinity : minSortedStarDefinitions[minIndex + 1].ValueRelativeMinimum();
379 var minNextRelativeStepSizeIncrease = Math.Min(currentNeededSpace / SumValues(maxSortedStarDefinitions), nextDefinitionRelativeMinSize - minDefinition.ValueRelativeMinimum());
381 while (minNextRelativeStepSizeIncrease > 0 && maxSortedStarDefinitions.Count > 0)
383 var maxDefinition = maxSortedStarDefinitions[0];
384 var maxNextStepSizeIncrease = maxDefinition.SizeValue * minNextRelativeStepSizeIncrease;
385 var maxNextStepRelativeSizeIncreate = Math.Min(minNextRelativeStepSizeIncrease, (maxDefinition.MaximumSize - maxDefinition.ActualSize) / maxDefinition.SizeValue);
388 minNextRelativeStepSizeIncrease -= maxNextStepRelativeSizeIncreate;
391 var maxDefinitionReachedItsMax = maxDefinition.ActualSize + maxNextStepSizeIncrease >= maxDefinition.MaximumSize;
394 foreach (var definition
in maxSortedStarDefinitions)
396 var absoluteIncrease = maxNextStepRelativeSizeIncreate * definition.SizeValue;
397 currentNeededSpace -= absoluteIncrease;
398 definition.ActualSize += absoluteIncrease;
402 if (maxDefinitionReachedItsMax)
404 var minNextStepSizeIncrease = minNextRelativeStepSizeIncrease * SumValues(maxSortedStarDefinitions);
405 maxSortedStarDefinitions.Remove(maxDefinition);
406 minNextRelativeStepSizeIncrease = minNextStepSizeIncrease / SumValues(maxSortedStarDefinitions);
410 neededOneStarSize = Math.Max(neededOneStarSize, maxDefinition.ActualSize / maxDefinition.SizeValue);
415 oneStarSize = Math.Max(oneStarSize, neededOneStarSize);
419 foreach (var starDefinition
in dimToStarDefinitions[dim])
420 starDefinition.ActualSize = starDefinition.ClampSizeByMinimumMaximum(oneStarSize * starDefinition.SizeValue);
423 neededSize[dim] += SumStripCurrentSize(definitions);
435 foreach (var definition
in definitions)
440 stripSize = definition.SizeValue;
442 definition.ActualSize = definition.ClampSizeByMinimumMaximum(stripSize);
449 CalculateStarStripSize(finalSizeWithoutMargins);
452 RebuildStripPositionCacheData();
455 var gridFinalSize = Vector3.Zero;
456 for (var dim = 0; dim < 3; dim++)
457 gridFinalSize[dim] = Math.Max(cachedStripIndexToStripPosition[dim][stripDefinitions[dim].Count], finalSizeWithoutMargins[dim]);
460 foreach (var child
in VisualChildrenCollection)
463 var gridPosition = GetElementGridPositions(child);
465 cachedStripIndexToStripPosition[0][gridPosition.X],
466 cachedStripIndexToStripPosition[1][gridPosition.Y],
467 cachedStripIndexToStripPosition[2][gridPosition.Z]);
470 child.DependencyProperties.Set(PanelArrangeMatrixPropertyKey, Matrix.Translation(position - gridFinalSize / 2));
473 var providedSize =
new Vector3(
474 SumStripCurrentSize(elementToStripDefinitions[0][child]),
475 SumStripCurrentSize(elementToStripDefinitions[1][child]),
476 SumStripCurrentSize(elementToStripDefinitions[2][child]));
479 child.Arrange(providedSize, IsCollapsed);
482 return gridFinalSize;
485 private void CalculateStarStripSize(
Vector3 finalSizeWithoutMargins)
488 for (var dim = 0; dim < 3; dim++)
490 starDefinitionsCopy.Clear();
491 starDefinitionsCopy.AddRange(dimToStarDefinitions[dim]);
494 var spaceTakenByFixedAndAutoStrips = SumStripAutoAndFixedSize(stripDefinitions[dim]);
497 var spaceRemainingForStarStrips = Math.Max(0f, finalSizeWithoutMargins[dim] - spaceTakenByFixedAndAutoStrips);
500 var starValuesSum = SumValues(starDefinitionsCopy);
503 var oneStarSpace = spaceRemainingForStarStrips / starValuesSum;
520 maxBoundedStarDefinitions.Clear();
521 minBoundedStarDefinitions.Clear();
524 foreach (var definition
in starDefinitionsCopy)
526 definition.ActualSize = definition.SizeValue * oneStarSpace;
527 if (definition.ActualSize < definition.MinimumSize)
529 definition.ActualSize = definition.MinimumSize;
530 minBoundedStarDefinitions.Add(definition);
532 else if (definition.ActualSize > definition.MaximumSize)
534 definition.ActualSize = definition.MaximumSize;
535 maxBoundedStarDefinitions.Add(definition);
540 var resultingSize = SumStripCurrentSize(starDefinitionsCopy);
543 var strimList = resultingSize < spaceRemainingForStarStrips ? maxBoundedStarDefinitions : minBoundedStarDefinitions;
546 spaceRemainingForStarStrips -= SumStripCurrentSize(strimList);
547 starValuesSum -= SumValues(strimList);
548 oneStarSpace = spaceRemainingForStarStrips / starValuesSum;
551 foreach (var definition
in strimList)
552 starDefinitionsCopy.Remove(definition);
555 while ((maxBoundedStarDefinitions.Count != 0 || minBoundedStarDefinitions.Count != 0) && starDefinitionsCopy.Count != 0);
561 base.OnLogicalChildRemoved(oldElement, index);
563 for (var dim = 0; dim < 3; dim++)
566 elementToStripDefinitions[dim].Remove(oldElement);
569 partialStarElementToStripDefinitions[dim].Remove(oldElement);
571 autoDefinedElements.Remove(oldElement);
577 base.OnLogicalChildAdded(newElement, index);
579 for (var dim = 0; dim < 3; dim++)
582 elementToStripDefinitions[dim][newElement] =
new List<StripDefinition>();
585 partialStarElementToStripDefinitions[dim][newElement] =
new List<StripDefinition>();
589 private void RebuildMeasureCacheData()
592 for (var dim = 0; dim < 3; dim++)
595 for (var index = 0; index < stripDefinitions[dim].Count; ++index)
597 if (stripIndexToNoStarElements[dim].Count <= index)
598 stripIndexToNoStarElements[dim].Add(
new List<UIElement>());
600 stripIndexToNoStarElements[dim][index].Clear();
604 foreach (var list
in elementToStripDefinitions[dim].Values)
608 foreach (var list
in partialStarElementToStripDefinitions[dim].Values)
611 autoDefinedElements.Clear();
614 foreach (var child
in VisualChildrenCollection)
616 var childPosition = GetElementGridPositions(child);
617 var childSpan = GetElementSpanValues(child);
619 for (var dim = 0; dim < 3; ++dim)
621 var childHasNoStarDefinitions =
true;
624 for (var i = childPosition[dim]; i < childPosition[dim] + childSpan[dim]; i++)
626 if (stripDefinitions[dim][i].Type ==
StripType.Star)
627 childHasNoStarDefinitions =
false;
628 else if (stripDefinitions[dim][i].Type ==
StripType.Auto)
629 autoDefinedElements.Add(child);
631 elementToStripDefinitions[dim][child].Add(stripDefinitions[dim][i]);
635 if (childHasNoStarDefinitions)
637 for (var i = childPosition[dim]; i < childPosition[dim] + childSpan[dim]; i++)
638 stripIndexToNoStarElements[dim][i].Add(child);
642 for (var i = childPosition[dim]; i < childPosition[dim] + childSpan[dim]; i++)
643 partialStarElementToStripDefinitions[dim][child].Add(stripDefinitions[dim][i]);
649 for (var dim = 0; dim < 3; ++dim)
651 dimToStarDefinitions[dim].Clear();
652 foreach (var definition
in stripDefinitions[dim])
654 dimToStarDefinitions[dim].Add(definition);
658 private void CheckChildrenPositionsAndAdjustGridSize()
661 foreach (var child
in VisualChildrenCollection)
663 var childLastStripPlusOne = GetElementGridPositions(child) + GetElementSpanValues(child);
664 for (var dim = 0; dim < 3; dim++)
666 if (stripDefinitions[dim].Count < childLastStripPlusOne[dim])
667 logger.Warning(
"Element 'Name={0}' is outside of the grid 'Name={1}' definition for [{2}]. Auto strip definitions will be added to complete the grid definition.", child, Name, dim == 0 ?
"Column" : dim == 1 ?
"Row" :
"Layer");
669 while (stripDefinitions[dim].Count < childLastStripPlusOne[dim])
670 stripDefinitions[dim].Add(
new StripDefinition(
StripType.Auto));
675 private void RebuildStripPositionCacheData()
678 for (var dim = 0; dim < 3; dim++)
681 cachedStripIndexToStripPosition[dim].Clear();
684 var startPosition = 0f;
685 for (var index = 0; index < stripDefinitions[dim].Count; index++)
687 cachedStripIndexToStripPosition[dim].Add(startPosition);
688 startPosition += stripDefinitions[dim][index].ActualSize;
690 cachedStripIndexToStripPosition[dim].Add(startPosition);
694 private float SumStripCurrentSize(StripDefinitionCollection definitions)
697 foreach (var def
in definitions)
698 sum += def.ActualSize;
703 private float SumStripCurrentSize(List<StripDefinition> definitions)
706 foreach (var def
in definitions)
707 sum += def.ActualSize;
712 private float SumStripAutoAndFixedSize(StripDefinitionCollection definitions)
715 foreach (var def
in definitions)
717 sum += def.ActualSize;
722 private float SumValues(List<StripDefinition> definitions)
725 foreach (var def
in definitions)
726 sum += def.SizeValue;
731 private void GetDistanceToSurroundingAnchors(List<float> stripPosition,
float position, out
Vector2 distances)
733 if (stripPosition.Count < 2)
735 distances = Vector2.Zero;
739 var validPosition = Math.Max(0, Math.Min(position, stripPosition[stripPosition.Count-1]));
742 while (index < stripPosition.Count-1 && stripPosition[index] <= validPosition)
745 distances =
new Vector2(stripPosition[index - 1], stripPosition[index]);
746 distances -=
new Vector2(validPosition, validPosition);
753 GetDistanceToSurroundingAnchors(cachedStripIndexToStripPosition[(
int)direction], position, out distances);
StripType
The different types of strip possible of a grid.
Provides a base class for all the User Interface elements in Paradox applications.
SiliconStudio.Paradox.Games.Mathematics.Vector2 Vector2
Represent the definition of a grid strip.
Represents a two dimensional mathematical vector.
Orientation
Defines the different orientations that a control or layout can have.
A collection of strip definitions
override Vector2 GetSurroudingAnchorDistances(Orientation direction, float position)
Get the distances to the previous and next anchors in the provided direction and from given position...
SiliconStudio.Paradox.Input.Keys Keys
Represents a three dimensional mathematical vector.
override Vector3 ArrangeOverride(Vector3 finalSizeWithoutMargins)
When overridden in a derived class, positions possible child elements and determines a size for a UIE...
override Vector3 MeasureOverride(Vector3 availableSizeWithoutMargins)
When overridden in a derived class, measures the size in layout required for possible child elements ...
Base implementation for ILogger.
override void OnLogicalChildRemoved(UIElement oldElement, int index)
Action to perform when a logical child is removed.
override void OnLogicalChildAdded(UIElement newElement, int index)
Action to perform when a logical child is added.
object Item
Gets the added or removed item (if dictionary, value only).
Represents the base primitive for all the grid-like controls
NotifyCollectionChangedAction Action
Gets the type of action performed. Allowed values are NotifyCollectionChangedAction.Add and NotifyCollectionChangedAction.Remove.
SiliconStudio.Core.Mathematics.Vector3 Vector3
Represents a grid control with adjustable columns, rows and layers.