Implement layout alignment and fixed dimensions

This commit is contained in:
Ben Olden-Cooligan 2022-10-15 21:58:42 -07:00
parent 14b1af5deb
commit d94658d970
9 changed files with 85 additions and 8 deletions

View File

@ -14,7 +14,8 @@ public class ControlWithLayoutAttributes : LayoutElement
public ControlWithLayoutAttributes(
ControlWithLayoutAttributes control, bool? center = null, bool? xScale = null, bool? yScale = null,
bool? autoSize = null, Padding? padding = null, int? width = null, int? height = null)
bool? autoSize = null, Padding? padding = null, int? width = null, int? height = null,
LayoutAlignment? alignment = null)
{
Control = control.Control;
Center = center ?? control.Center;
@ -24,6 +25,7 @@ public class ControlWithLayoutAttributes : LayoutElement
Padding = padding ?? control.Padding;
Width = width ?? control.Width;
Height = height ?? control.Height;
Alignment = alignment ?? control.Alignment;
}
public static implicit operator ControlWithLayoutAttributes(Control control) =>
@ -72,6 +74,7 @@ public class ControlWithLayoutAttributes : LayoutElement
var text = Control is TextControl txt ? $"\"{txt.Text}\" " : "";
Debug.WriteLine($"{new string(' ', context.Depth)}{text} layout with bounds {bounds}");
}
bounds.Size = UpdateFixedDimensions(bounds.Size);
if (Control != null)
{
var location = new PointF(bounds.X + Padding.Left, bounds.Y + Padding.Right);
@ -90,9 +93,23 @@ public class ControlWithLayoutAttributes : LayoutElement
EnsureIsAdded(context);
size = EtoPlatform.Current.GetPreferredSize(Control, parentBounds.Size);
}
size = UpdateFixedDimensions(size);
return new SizeF(size.Width + Padding.Horizontal, size.Height + Padding.Vertical);
}
private SizeF UpdateFixedDimensions(SizeF size)
{
if (Width != null)
{
size.Width = Width.Value;
}
if (Height != null)
{
size.Height = Height.Value;
}
return size;
}
private void EnsureIsAdded(LayoutContext context)
{
if (context.IsFirstLayout && !_isAdded)

View File

@ -64,6 +64,12 @@ public static class EtoLayoutExtensions
new ControlWithLayoutAttributes(control, xScale: true);
public static ControlWithLayoutAttributes YScale(this Control control) =>
new ControlWithLayoutAttributes(control, yScale: true);
public static ControlWithLayoutAttributes AlignCenter(this Control control) =>
new ControlWithLayoutAttributes(control, alignment: LayoutAlignment.Center);
public static ControlWithLayoutAttributes AlignLeading(this Control control) =>
new ControlWithLayoutAttributes(control, alignment: LayoutAlignment.Leading);
public static ControlWithLayoutAttributes AlignTrailing(this Control control) =>
new ControlWithLayoutAttributes(control, alignment: LayoutAlignment.Trailing);
public static ControlWithLayoutAttributes AutoSize(this Control control) =>
new ControlWithLayoutAttributes(control, autoSize: true);
public static ControlWithLayoutAttributes Padding(this Control control, Padding padding) =>
@ -85,6 +91,12 @@ public static class EtoLayoutExtensions
new ControlWithLayoutAttributes(control, xScale: true);
public static ControlWithLayoutAttributes YScale(this ControlWithLayoutAttributes control) =>
new ControlWithLayoutAttributes(control, yScale: true);
public static ControlWithLayoutAttributes AlignCenter(this ControlWithLayoutAttributes control) =>
new ControlWithLayoutAttributes(control, alignment: LayoutAlignment.Center);
public static ControlWithLayoutAttributes AlignLeading(this ControlWithLayoutAttributes control) =>
new ControlWithLayoutAttributes(control, alignment: LayoutAlignment.Leading);
public static ControlWithLayoutAttributes AlignTrailing(this ControlWithLayoutAttributes control) =>
new ControlWithLayoutAttributes(control, alignment: LayoutAlignment.Trailing);
public static ControlWithLayoutAttributes AutoSize(this ControlWithLayoutAttributes control) =>
new ControlWithLayoutAttributes(control, autoSize: true);
public static ControlWithLayoutAttributes Padding(this ControlWithLayoutAttributes control, Padding padding) =>

View File

@ -0,0 +1,9 @@
namespace NAPS2.EtoForms.Layout;
public enum LayoutAlignment
{
Fill,
Leading,
Center,
Trailing
}

View File

@ -40,6 +40,12 @@ public class LayoutColumn : LayoutLine<LayoutRow>
return position;
}
protected override PointF UpdateOrthogonalPosition(PointF position, float delta)
{
position.X += delta;
return position;
}
protected override SizeF UpdateTotalSize(SizeF size, SizeF childSize, int spacing)
{
size.Height += childSize.Height + spacing;

View File

@ -9,6 +9,7 @@ public abstract class LayoutElement
protected internal bool XScale { get; set; }
protected internal bool YScale { get; set; }
protected internal LayoutAlignment Alignment { get; set; }
public abstract void AddTo(DynamicLayout layout);

View File

@ -13,6 +13,8 @@ public abstract class LayoutLine<TOrthogonal> : LayoutContainer
protected abstract PointF UpdatePosition(PointF position, float delta);
protected abstract PointF UpdateOrthogonalPosition(PointF position, float delta);
protected abstract SizeF UpdateTotalSize(SizeF size, SizeF childSize, int spacing);
public override void DoLayout(LayoutContext context, RectangleF bounds)
@ -27,15 +29,40 @@ public abstract class LayoutLine<TOrthogonal> : LayoutContainer
var spacing = Spacing ?? context.DefaultSpacing;
UpdateCellLengthsForAvailableSpace(cellLengths, cellScaling, bounds, spacing);
// The "cell" size and origin define the space the control can fit in, while the "child" size and origin define
// the actual space the control fills. The child always fills the cell length-wise, but breadth-wise it depends
// on the control alignment.
var cellOrigin = bounds.Location;
for (int i = 0; i < Children.Length; i++)
{
var child = Children[i];
var cellSize = GetSize(cellLengths[i], GetBreadth(bounds.Size));
Children[i].DoLayout(childContext, new RectangleF(cellOrigin, cellSize));
cellOrigin = UpdatePosition(cellOrigin, GetLength(cellSize) + spacing);
GetChildSizeAndOrigin(child, childContext, cellSize, cellOrigin,
out var childSize, out var childOrigin);
child.DoLayout(childContext, new RectangleF(childOrigin, childSize));
cellOrigin = UpdatePosition(cellOrigin, GetLength(childSize) + spacing);
}
}
private void GetChildSizeAndOrigin(LayoutElement child, LayoutContext childContext,
SizeF cellSize, PointF cellOrigin, out SizeF childSize, out PointF childOrigin)
{
var breadth = GetBreadth(
child.Alignment == LayoutAlignment.Fill
? cellSize
: child.GetPreferredSize(childContext, new RectangleF(cellOrigin, cellSize)));
var remainingBreadth = GetBreadth(cellSize) - breadth;
var alignmentOffset = child.Alignment switch
{
LayoutAlignment.Leading => 0,
LayoutAlignment.Center => remainingBreadth / 2,
LayoutAlignment.Trailing => remainingBreadth,
_ => 0
};
childSize = GetSize(GetLength(cellSize), breadth);
childOrigin = UpdateOrthogonalPosition(cellOrigin, alignmentOffset);
}
public override SizeF GetPreferredSize(LayoutContext context, RectangleF parentBounds)
{
var childContext = GetChildContext(context, parentBounds);

View File

@ -46,6 +46,12 @@ public class LayoutRow : LayoutLine<LayoutColumn>
return position;
}
protected override PointF UpdateOrthogonalPosition(PointF position, float delta)
{
position.Y += delta;
return position;
}
protected override SizeF UpdateTotalSize(SizeF size, SizeF childSize, int spacing)
{
size.Width += childSize.Width + spacing;

View File

@ -131,7 +131,7 @@ public class EditProfileForm : EtoDialogBase
C.Label(UiStrings.BrightnessLabel),
L.Row(
_brightnessSlider.XScale(),
_brightnessText.Width(40)
_brightnessText.Width(50).AlignCenter()
)
).XScale(),
L.Column(
@ -144,7 +144,7 @@ public class EditProfileForm : EtoDialogBase
C.Label(UiStrings.ContrastLabel),
L.Row(
_contrastSlider.XScale(),
_contrastText.Width(40)
_contrastText.Width(50).AlignCenter()
)
).XScale()
),
@ -166,10 +166,9 @@ public class EditProfileForm : EtoDialogBase
var buffer = new Size(130, 0);
FormStateController.MinimumClientSize = naturalSize;
FormStateController.DefaultClientSize = naturalSize + buffer;
FormStateController.RestoreFormState = false;
FormStateController.RestoreFormState = true;
}
public bool Result => _result;
public ScanProfile ScanProfile

View File

@ -131,7 +131,7 @@ public class ProfilesForm : EtoDialogBase
L.Row(
_listView.Control.XScale(),
C.Button(_scanCommand, Icons.control_play_blue.ToEtoImage(), ButtonImagePosition.Above).AutoSize()
.Height(100)
.Height(80)
).Aligned().YScale(),
L.Row(
L.Column(