//
// PosDim.cs: Pos and Dim objects for view dimensions.
//
// Authors:
// Miguel de Icaza (miguel@gnome.org)
//
using System;
namespace Terminal.Gui {
///
/// Describes a position which can be an absolute value, a percentage, centered, or
/// relative to the ending dimension. Integer values are implicitly convertible to
/// an absolute Pos. These objects are created using the static methods Percent,
/// AnchorEnd and Center. The Pos objects can be combined with the addition and
/// subtraction operators.
///
///
///
/// Use the Pos objects on the X or Y properties of a view to control the position.
///
///
/// These can be used to set the absolute position, when merely assigning an
/// integer value (via the implicit integer to Pos conversion), and they can be combined
/// to produce more useful layouts, like: Pos.Center - 3, which would shift the postion
/// of the view 3 characters to the left after centering for example.
///
///
public class Pos {
internal virtual int Anchor (int width)
{
return 0;
}
class PosFactor : Pos {
float factor;
public PosFactor (float n)
{
this.factor = n;
}
internal override int Anchor (int width)
{
return (int)(width * factor);
}
public override string ToString ()
{
return $"Pos.Factor({factor})";
}
}
///
/// Creates a percentage Pos object
///
/// The percent Pos object.
/// A value between 0 and 100 representing the percentage.
public static Pos Percent (float n)
{
if (n < 0 || n > 100)
throw new ArgumentException ("Percent value must be between 0 and 100");
return new PosFactor (n / 100);
}
static PosAnchorEnd endNoMargin;
class PosAnchorEnd : Pos {
int n;
public PosAnchorEnd (int n)
{
this.n = n;
}
internal override int Anchor (int width)
{
return width - n;
}
public override string ToString ()
{
return $"Pos.AnchorEnd(margin={n})";
}
}
///
/// Creates a Pos object that is anchored to the end of the dimension, useful to flush
/// the layout from the end.
///
/// The Pos object anchored to the end (the bottom or the right side).
/// Optional margin to set aside.
public static Pos AnchorEnd (int margin = 0)
{
if (margin < 0)
throw new ArgumentException ("Margin must be positive");
if (margin == 0) {
if (endNoMargin == null)
endNoMargin = new PosAnchorEnd (0);
return endNoMargin;
}
return new PosAnchorEnd (margin);
}
internal class PosCenter : Pos {
internal override int Anchor (int width)
{
return width / 2;
}
public override string ToString ()
{
return "Pos.Center";
}
}
static PosCenter pCenter;
///
/// Returns a Pos object that can be used to center the views.
///
/// The center Pos.
public static Pos Center ()
{
if (pCenter == null)
pCenter = new PosCenter ();
return pCenter;
}
class PosAbsolute : Pos {
int n;
public PosAbsolute (int n) { this.n = n; }
public override string ToString ()
{
return $"Pos.Absolute({n})";
}
internal override int Anchor (int width)
{
return n;
}
}
///
/// Creates an Absolute Pos from the specified integer value.
///
/// The Absolute Pos.
/// The value to convert to the pos.
public static implicit operator Pos (int n)
{
return new PosAbsolute (n);
}
class PosCombine : Pos {
Pos left, right;
bool add;
public PosCombine (bool add, Pos left, Pos right)
{
this.left = left;
this.right = right;
this.add = add;
}
internal override int Anchor (int width)
{
var la = left.Anchor (width);
var ra = right.Anchor (width);
if (add)
return la + ra;
else
return la - ra;
}
}
///
/// Adds a to a , yielding a new .
///
/// The first to add.
/// The second to add.
/// The that is the sum of the values of left and right.
public static Pos operator + (Pos left, Pos right)
{
return new PosCombine (true, left, right);
}
///
/// Subtracts a from a , yielding a new .
///
/// The to subtract from (the minuend).
/// The to subtract (the subtrahend).
/// The that is the left minus right.
public static Pos operator - (Pos left, Pos right)
{
return new PosCombine (false, left, right);
}
}
///
///
///
///
/// Use the Dim objects on the Width or Height properties of a view to control the position.
///
///
/// These can be used to set the absolute position, when merely assigning an
/// integer value (via the implicit integer to Pos conversion), and they can be combined
/// to produce more useful layouts, like: Pos.Center - 3, which would shift the postion
/// of the view 3 characters to the left after centering for example.
///
///
public class Dim {
internal virtual int Anchor (int width)
{
return 0;
}
class DimFactor : Dim {
float factor;
public DimFactor (float n)
{
this.factor = n;
}
internal override int Anchor (int width)
{
return (int)(width * factor);
}
public override string ToString ()
{
return $"Dim.Factor({factor})";
}
}
///
/// Creates a percentage Dim object
///
/// The percent Dim object.
/// A value between 0 and 100 representing the percentage.
public static Dim Percent (float n)
{
if (n < 0 || n > 100)
throw new ArgumentException ("Percent value must be between 0 and 100");
return new DimFactor (n / 100);
}
class DimAbsolute : Dim {
int n;
public DimAbsolute (int n) { this.n = n; }
public override string ToString ()
{
return $"Dim.Absolute({n})";
}
internal override int Anchor (int width)
{
return n;
}
}
class DimFill : Dim {
int margin;
public DimFill (int margin) { this.margin = margin; }
public override string ToString ()
{
return $"Dim.Fill(margin={margin})";
}
internal override int Anchor (int width)
{
return width-margin;
}
}
static DimFill zeroMargin;
///
/// Creates a Dim object that fills the dimension, but leaves the specified number of colums for a margin.
///
/// The Fill dimension.
/// Margin to use.
public static Dim Fill (int margin = 0)
{
if (margin == 0) {
if (zeroMargin == null)
zeroMargin = new DimFill (0);
return zeroMargin;
}
return new DimFill (margin);
}
///
/// Creates an Absolute Pos from the specified integer value.
///
/// The Absolute Pos.
/// The value to convert to the pos.
public static implicit operator Dim (int n)
{
return new DimAbsolute (n);
}
class DimCombine : Dim {
Dim left, right;
bool add;
public DimCombine (bool add, Dim left, Dim right)
{
this.left = left;
this.right = right;
this.add = add;
}
internal override int Anchor (int width)
{
var la = left.Anchor (width);
var ra = right.Anchor (width);
if (add)
return la + ra;
else
return la - ra;
}
}
///
/// Adds a to a , yielding a new .
///
/// The first to add.
/// The second to add.
/// The that is the sum of the values of left and right.
public static Dim operator + (Dim left, Dim right)
{
return new DimCombine (true, left, right);
}
///
/// Subtracts a from a , yielding a new .
///
/// The to subtract from (the minuend).
/// The to subtract (the subtrahend).
/// The that is the left minus right.
public static Dim operator - (Dim left, Dim right)
{
return new DimCombine (false, left, right);
}
}
}