using System;
using System.Text;
using Terminal.Gui;
namespace UICatalog.Scenarios;
///
/// A Button that can expand or collapse a view.
///
///
///
/// Add this button to a view's Border to allow the user to expand or collapse the view via either the keyboard
/// (F4) or mouse.
///
///
/// If is set to , the button will appear
/// at the top/right.
/// If is set to , the button will
/// appear at the
/// bottom/left.
///
///
///
/// private void MyView_Initialized (object sender, EventArgs e)
/// {
/// Border.Add(new ExpanderButton ());
/// ...
///
public class ExpanderButton : Button
{
public ExpanderButton ()
{
CanFocus = false;
Width = 1;
Height = 1;
NoDecorations = true;
NoPadding = true;
ShadowStyle = ShadowStyle.None;
AddCommand (Command.HotKey, Toggle);
AddCommand (Command.ToggleExpandCollapse, Toggle);
KeyBindings.Add (Key.F4, Command.ToggleExpandCollapse);
Orientation = Orientation.Vertical;
Initialized += ExpanderButton_Initialized;
}
private void ExpanderButton_Initialized (object sender, EventArgs e)
{
ExpandOrCollapse (Collapsed);
}
private Orientation _orientation = Orientation.Horizontal;
/// Orientation.
///
///
/// If is set to , the button will appear at the
/// top/right.
/// If is set to , the button will appear at the
/// bottom/left.
///
///
public Orientation Orientation
{
get => _orientation;
set => OnOrientationChanging (value);
}
/// Called when the orientation is changing. Invokes the event.
///
/// True of the event was cancelled.
protected virtual bool OnOrientationChanging (Orientation newOrientation)
{
var args = new OrientationEventArgs (newOrientation);
OrientationChanging?.Invoke (this, args);
if (!args.Cancel)
{
_orientation = newOrientation;
if (Orientation == Orientation.Vertical)
{
X = Pos.AnchorEnd ();
Y = 0;
CollapsedGlyph = new ('\u21d1'); // ⇑
ExpandedGlyph = new ('\u21d3'); // ⇓
}
else
{
X = 0;
Y = Pos.AnchorEnd ();
CollapsedGlyph = new ('\u21d0'); // ⇐
ExpandedGlyph = new ('\u21d2'); // ⇒
}
ExpandOrCollapse (Collapsed);
}
return args.Cancel;
}
///
/// Fired when the orientation has changed. Can be cancelled by setting
/// to true.
///
public event EventHandler OrientationChanging;
///
/// The glyph to display when the view is collapsed.
///
public Rune CollapsedGlyph { get; set; }
///
/// The glyph to display when the view is expanded.
///
public Rune ExpandedGlyph { get; set; }
private bool _collapsed;
///
/// Gets or sets a value indicating whether the view is collapsed.
///
public bool Collapsed
{
get => _collapsed;
set => OnCollapsedChanging (value);
}
/// Called when the orientation is changing. Invokes the event.
///
///
/// True of the event was cancelled.
protected virtual bool OnCollapsedChanging (bool newValue)
{
CancelEventArgs args = new (ref _collapsed, ref newValue);
CollapsedChanging?.Invoke (this, args);
if (!args.Cancel)
{
_collapsed = args.NewValue;
ExpandOrCollapse (_collapsed);
View superView = SuperView;
if (superView is Adornment adornment)
{
superView = adornment.Parent;
}
foreach (View subview in superView.Subviews)
{
subview.Visible = !Collapsed;
subview.Enabled = !Collapsed;
}
}
return args.Cancel;
}
///
/// Fired when the orientation has changed. Can be cancelled by setting
/// to true.
///
public event EventHandler> CollapsedChanging;
///
/// Collapses or Expands the view.
///
///
public bool? Toggle ()
{
Collapsed = !Collapsed;
return true;
}
private Dim _previousDim;
private void ExpandOrCollapse (bool collapse)
{
Text = $"{(Collapsed ? CollapsedGlyph : ExpandedGlyph)}";
View superView = SuperView;
if (superView is Adornment adornment)
{
superView = adornment.Parent;
}
if (superView is null)
{
return;
}
if (collapse)
{
// Collapse
if (Orientation == Orientation.Vertical)
{
_previousDim = superView.Height;
superView.Height = 1;
}
else
{
_previousDim = superView.Width;
superView.Width = 1;
}
}
else
{
if (_previousDim is null)
{
return;
}
// Expand
if (Orientation == Orientation.Vertical)
{
superView.Height = _previousDim;
}
else
{
superView.Width = _previousDim;
}
}
}
}