namespace Terminal.Gui;
// TODO: v2 - Missing 3D effect - 3D effects will be drawn by a mechanism separate from Adornments
// TODO: v2 - If a Adornment has focus, navigation keys (e.g Command.NextView) should cycle through SubViews of the Adornments
// QUESTION: How does a user navigate out of an Adornment to another Adornment, or back into the Parent's SubViews?
///
/// Adornments are a special form of that appear outside of the :
/// , , and . They are defined using the
/// class, which specifies the thickness of the sides of a rectangle.
///
///
///
/// There is no prevision for creating additional subclasses of Adornment. It is not abstract to enable unit
/// testing.
///
/// Each of , , and can be customized.
///
public class Adornment : View
{
private Thickness _thickness = Thickness.Empty;
///
public Adornment ()
{
/* Do nothing; A parameter-less constructor is required to support all views unit tests. */
}
/// Constructs a new adornment for the view specified by .
///
public Adornment (View parent) { Parent = parent; }
///
/// Gets the rectangle that describes the area of the Adornment. The Location is always (0,0).
/// The size is the size of the Frame
///
public override Rectangle Bounds
{
get => Frame with { Location = Point.Empty };
set => throw new InvalidOperationException ("It makes no sense to set Bounds of a Thickness.");
}
/// The Parent of this Adornment (the View this Adornment surrounds).
///
/// Adornments are distinguished from typical View classes in that they are not sub-views, but have a parent/child
/// relationship with their containing View.
///
public View Parent { get; set; }
///
/// Adornments cannot be used as sub-views (see ); this method always throws an
/// . TODO: Are we sure?
///
public override View SuperView
{
get => null;
set => throw new NotImplementedException ();
}
///
/// Adornments only render to their 's or Parent's SuperView's LineCanvas, so setting this
/// property throws an .
///
public override bool SuperViewRendersLineCanvas
{
get => false; // throw new NotImplementedException ();
set => throw new NotImplementedException ();
}
/// Defines the rectangle that the will use to draw its content.
public Thickness Thickness
{
get => _thickness;
set
{
Thickness prev = _thickness;
_thickness = value;
if (prev != _thickness)
{
Parent?.LayoutAdornments ();
OnThicknessChanged (prev);
}
}
}
///
public override Rectangle FrameToScreen ()
{
if (Parent is null)
{
return Frame;
}
// Adornments are *Children* of a View, not SubViews. Thus View.FrameToScreen will not work.
// To get the screen-relative coordinates of an Adornment, we need get the parent's Frame
// in screen coords, and add our Frame location to it.
Rectangle parent = Parent.FrameToScreen ();
return new (new (parent.X + Frame.X, parent.Y + Frame.Y), Frame.Size);
}
/// Does nothing for Adornment
///
public override bool OnDrawAdornments () { return false; }
/// Redraws the Adornments that comprise the .
public override void OnDrawContent (Rectangle contentArea)
{
if (Thickness == Thickness.Empty)
{
return;
}
Rectangle screenBounds = BoundsToScreen (contentArea);
Attribute normalAttr = GetNormalColor ();
Driver.SetAttribute (normalAttr);
// This just draws/clears the thickness, not the insides.
Thickness.Draw (screenBounds, ToString ());
if (!string.IsNullOrEmpty (TextFormatter.Text))
{
if (TextFormatter is { })
{
TextFormatter.Size = Frame.Size;
TextFormatter.NeedsFormat = true;
}
}
TextFormatter?.Draw (screenBounds, normalAttr, normalAttr, Rectangle.Empty);
//base.OnDrawContent (contentArea);
}
/// Does nothing for Adornment
///
public override bool OnRenderLineCanvas () { return false; }
/// Called whenever the property changes.
public virtual void OnThicknessChanged (Thickness previousThickness)
{
ThicknessChanged?.Invoke (
this,
new() { Thickness = Thickness, PreviousThickness = previousThickness }
);
}
/// Fired whenever the property changes.
public event EventHandler ThicknessChanged;
internal override Adornment CreateAdornment (Type adornmentType)
{
/* Do nothing - Adornments do not have Adornments */
return null;
}
internal override void LayoutAdornments ()
{
/* Do nothing - Adornments do not have Adornments */
}
}