DimAuto.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. #nullable enable
  2. namespace Terminal.Gui;
  3. /// <summary>
  4. /// Represents a dimension that automatically sizes the view to fit all the view's Content, SubViews, and/or Text.
  5. /// </summary>
  6. /// <remarks>
  7. /// <para>
  8. /// See <see cref="DimAutoStyle"/>.
  9. /// </para>
  10. /// <para>
  11. /// This is a low-level API that is typically used internally by the layout system. Use the various static
  12. /// methods on the <see cref="Dim"/> class to create <see cref="Dim"/> objects instead.
  13. /// </para>
  14. /// </remarks>
  15. public class DimAuto () : Dim
  16. {
  17. private readonly Dim? _maximumContentDim;
  18. /// <summary>
  19. /// Gets the maximum dimension the View's ContentSize will be fit to. NOT CURRENTLY SUPPORTED.
  20. /// </summary>
  21. // ReSharper disable once ConvertToAutoProperty
  22. public required Dim? MaximumContentDim
  23. {
  24. get => _maximumContentDim;
  25. init => _maximumContentDim = value;
  26. }
  27. private readonly Dim? _minimumContentDim;
  28. /// <summary>
  29. /// Gets the minimum dimension the View's ContentSize will be constrained to.
  30. /// </summary>
  31. // ReSharper disable once ConvertToAutoProperty
  32. public required Dim? MinimumContentDim
  33. {
  34. get => _minimumContentDim;
  35. init => _minimumContentDim = value;
  36. }
  37. private readonly DimAutoStyle _style;
  38. /// <summary>
  39. /// Gets the style of the DimAuto.
  40. /// </summary>
  41. // ReSharper disable once ConvertToAutoProperty
  42. public required DimAutoStyle Style
  43. {
  44. get => _style;
  45. init => _style = value;
  46. }
  47. /// <inheritdoc/>
  48. public override string ToString () { return $"Auto({Style},{MinimumContentDim},{MaximumContentDim})"; }
  49. internal override int Calculate (int location, int superviewContentSize, View us, Dimension dimension)
  50. {
  51. var textSize = 0;
  52. var subviewsSize = 0;
  53. int autoMin = MinimumContentDim?.GetAnchor (superviewContentSize) ?? 0;
  54. if (Style.FastHasFlags (DimAutoStyle.Text))
  55. {
  56. textSize = int.Max (autoMin, dimension == Dimension.Width ? us.TextFormatter.Size.Width : us.TextFormatter.Size.Height);
  57. }
  58. if (Style.FastHasFlags (DimAutoStyle.Content))
  59. {
  60. if (us._contentSize is { })
  61. {
  62. subviewsSize = dimension == Dimension.Width ? us.ContentSize.Width : us.ContentSize.Height;
  63. }
  64. else
  65. {
  66. // TODO: This whole body of code is a WIP (for https://github.com/gui-cs/Terminal.Gui/pull/3451).
  67. subviewsSize = 0;
  68. List<View> subviews;
  69. if (dimension == Dimension.Width)
  70. {
  71. subviews = us.Subviews.Where (v => v.X is not PosAnchorEnd && v.Width is not DimFill).ToList ();
  72. }
  73. else
  74. {
  75. subviews = us.Subviews.Where (v => v.Y is not PosAnchorEnd && v.Height is not DimFill).ToList ();
  76. }
  77. for (var i = 0; i < subviews.Count; i++)
  78. {
  79. View v = subviews [i];
  80. int size = dimension == Dimension.Width ? v.Frame.X + v.Frame.Width : v.Frame.Y + v.Frame.Height;
  81. if (size > subviewsSize)
  82. {
  83. subviewsSize = size;
  84. }
  85. }
  86. if (dimension == Dimension.Width)
  87. {
  88. subviews = us.Subviews.Where (v => v.X is PosAnchorEnd).ToList ();
  89. }
  90. else
  91. {
  92. subviews = us.Subviews.Where (v => v.Y is PosAnchorEnd).ToList ();
  93. }
  94. int maxAnchorEnd = 0;
  95. for (var i = 0; i < subviews.Count; i++)
  96. {
  97. View v = subviews [i];
  98. maxAnchorEnd = dimension == Dimension.Width ? v.Frame.Width : v.Frame.Height;
  99. }
  100. subviewsSize += maxAnchorEnd;
  101. if (dimension == Dimension.Width)
  102. {
  103. subviews = us.Subviews.Where (v => v.Width is DimFill).ToList ();
  104. }
  105. else
  106. {
  107. subviews = us.Subviews.Where (v => v.Height is DimFill).ToList ();
  108. }
  109. for (var i = 0; i < subviews.Count; i++)
  110. {
  111. View v = subviews [i];
  112. if (dimension == Dimension.Width)
  113. {
  114. v.SetRelativeLayout (new Size (autoMin - subviewsSize, 0));
  115. }
  116. else
  117. {
  118. v.SetRelativeLayout (new Size (0, autoMin - subviewsSize));
  119. }
  120. }
  121. }
  122. }
  123. // All sizes here are content-relative; ignoring adornments.
  124. // We take the largest of text and content.
  125. int max = int.Max (textSize, subviewsSize);
  126. // And, if min: is set, it wins if larger
  127. max = int.Max (max, autoMin);
  128. // Factor in adornments
  129. Thickness thickness = us.GetAdornmentsThickness ();
  130. max += dimension switch
  131. {
  132. Dimension.Width => thickness.Horizontal,
  133. Dimension.Height => thickness.Vertical,
  134. Dimension.None => 0,
  135. _ => throw new ArgumentOutOfRangeException (nameof (dimension), dimension, null)
  136. };
  137. return int.Min (max, MaximumContentDim?.GetAnchor (superviewContentSize) ?? max);
  138. }
  139. internal override bool ReferencesOtherViews ()
  140. {
  141. // BUGBUG: This is not correct. _contentSize may be null.
  142. return false; //_style.HasFlag (DimAutoStyle.Content);
  143. }
  144. /// <inheritdoc/>
  145. public override bool Equals (object? other)
  146. {
  147. if (other is not DimAuto auto)
  148. {
  149. return false;
  150. }
  151. return auto.MinimumContentDim == MinimumContentDim &&
  152. auto.MaximumContentDim == MaximumContentDim &&
  153. auto.Style == Style;
  154. }
  155. /// <inheritdoc/>
  156. public override int GetHashCode ()
  157. {
  158. return HashCode.Combine (MinimumContentDim, MaximumContentDim, Style);
  159. }
  160. }