//
// Authors:
// Miguel de Icaza (miguel@gnome.org)
//
// NOTE: Window is functionally identical to FrameView with the following exceptions.
// - Window is a Toplevel
// - FrameView Does not support padding (but should)
// - FrameView Does not support mouse dragging
// - FrameView Does not support IEnumerable
// Any updates done here should probably be done in FrameView as well; TODO: Merge these classes
using System;
using System.Collections;
using System.Text.Json.Serialization;
using NStack;
using Terminal.Gui.Configuration;
using static Terminal.Gui.Configuration.ConfigurationManager;
namespace Terminal.Gui {
///
/// A that draws a border around its with a Title at the top.
///
///
/// The 'client area' of a is a rectangle deflated by one or more rows/columns from . A this time there is no
/// API to determine this rectangle.
///
public class Window : Toplevel {
///
/// Initializes a new instance of the class with an optional title using positioning.
///
/// Superview-relative rectangle specifying the location and size
/// Title
///
/// This constructor initializes a Window with a of . Use constructors
/// that do not take Rect parameters to initialize a Window with .
///
public Window (Rect frame, ustring title = null) : this (frame, title, padding: 0, border: null)
{
}
///
/// Initializes a new instance of the class with an optional title using positioning.
///
/// Title.
///
/// This constructor initializes a View with a of .
/// Use , , , and properties to dynamically control the size and location of the view.
///
public Window (ustring title = null) : this (title, padding: 0, border: null)
{
}
///
/// Initializes a new instance of the class using positioning.
///
public Window () : this (title: null) { }
///
/// Initializes a new instance of the using positioning with the specified frame for its location, with the specified frame padding,
/// and an optional title.
///
/// Superview-relative rectangle specifying the location and size
/// Title
/// Number of characters to use for padding of the drawn frame.
/// The .
///
/// This constructor initializes a Window with a of . Use constructors
/// that do not take Rect parameters to initialize a Window with of
///
public Window (Rect frame, ustring title = null, int padding = 0, Border border = null) : base (frame)
{
Initialize (title, frame, padding, border);
}
///
/// Initializes a new instance of the using positioning,
/// and an optional title.
///
/// Title.
/// Number of characters to use for padding of the drawn frame.
/// The .
///
/// This constructor initializes a View with a of .
/// Use , , , and properties to dynamically control the size and location of the view.
///
public Window (ustring title = null, int padding = 0, Border border = null) : base ()
{
Initialize (title, Rect.Empty, padding, border);
}
///
/// The default for . The default is .
///
///
/// This property can be set in a Theme to change the default for all s.
///
///[SerializableConfigurationProperty (Scope = typeof (ThemeScope)), JsonConverter (typeof (JsonStringEnumConverter))]
public static BorderStyle DefaultBorderStyle { get; set; } = BorderStyle.Single;
void Initialize (ustring title, Rect frame, int padding = 0, Border border = null)
{
CanFocus = true;
ColorScheme = Colors.Base;
if (title == null) title = ustring.Empty;
Title = title;
if (border == null) {
Border = new Border () {
BorderStyle = DefaultBorderStyle,
Padding = new Thickness (padding),
//Title = title
};
} else {
Border = border;
}
}
///
public override void Add (View view)
{
base.Add (view);
if (view.CanFocus) {
CanFocus = true;
}
AddMenuStatusBar (view);
}
///
public override void Remove (View view)
{
if (view == null) {
return;
}
SetNeedsDisplay ();
base.Remove (view);
RemoveMenuStatusBar (view);
}
/////
//public override void RemoveAll ()
//{
// contentView.RemoveAll ();
//}
/////
//public override void Redraw (Rect bounds)
//{
// var padding = Border.GetSumThickness ();
// var scrRect = ViewToScreen (new Rect (0, 0, Frame.Width, Frame.Height));
// if (!NeedDisplay.IsEmpty || ChildNeedsDisplay || LayoutNeeded) {
// Driver.SetAttribute (GetNormalColor ());
// Clear ();
// contentView.SetNeedsDisplay ();
// }
// var savedClip = contentView.ClipToBounds ();
// // Redraw our contentView
// // DONE: smartly constrict contentView.Bounds to just be what intersects with the 'bounds' we were passed
// contentView.Redraw (!NeedDisplay.IsEmpty || ChildNeedsDisplay || LayoutNeeded ? contentView.Bounds : bounds);
// Driver.Clip = savedClip;
// ClearLayoutNeeded ();
// ClearNeedsDisplay ();
// Driver.SetAttribute (GetNormalColor ());
// //Driver.DrawWindowFrame (scrRect, padding.Left + borderLength, padding.Top + borderLength, padding.Right + borderLength, padding.Bottom + borderLength,
// // Border.BorderStyle != BorderStyle.None, fill: true, Border.BorderStyle);
// Border.DrawContent (this, false);
// if (HasFocus)
// Driver.SetAttribute (ColorScheme.HotNormal);
// if (Border.DrawMarginFrame)
// Driver.DrawWindowTitle (scrRect, Title, padding.Left, padding.Top, padding.Right, padding.Bottom);
// Driver.SetAttribute (GetNormalColor ());
//}
/////
//public override void OnCanFocusChanged ()
//{
// if (contentView != null) {
// contentView.CanFocus = CanFocus;
// }
// base.OnCanFocusChanged ();
//}
/////
///// The text displayed by the .
/////
//public override ustring Text {
// get => contentView?.Text;
// set {
// base.Text = value;
// if (contentView != null) {
// contentView.Text = value;
// }
// }
//}
/////
///// Controls the text-alignment property of the label, changing it will redisplay the .
/////
///// The text alignment.
//public override TextAlignment TextAlignment {
// get => contentView.TextAlignment;
// set {
// base.TextAlignment = contentView.TextAlignment = value;
// }
//}
///
/// Event arguments for change events.
///
public class TitleEventArgs : EventArgs {
///
/// The new Window Title.
///
public ustring NewTitle { get; set; }
///
/// The old Window Title.
///
public ustring OldTitle { get; set; }
///
/// Flag which allows canceling the Title change.
///
public bool Cancel { get; set; }
///
/// Initializes a new instance of
///
/// The that is/has been replaced.
/// The new to be replaced.
public TitleEventArgs (ustring oldTitle, ustring newTitle)
{
OldTitle = oldTitle;
NewTitle = newTitle;
}
}
///
/// Called before the changes. Invokes the event, which can be cancelled.
///
/// The that is/has been replaced.
/// The new to be replaced.
/// `true` if an event handler canceled the Title change.
public virtual bool OnTitleChanging (ustring oldTitle, ustring newTitle)
{
var args = new TitleEventArgs (oldTitle, newTitle);
TitleChanging?.Invoke (args);
return args.Cancel;
}
///
/// Event fired when the is changing. Set to
/// `true` to cancel the Title change.
///
public event Action TitleChanging;
///
/// Called when the has been changed. Invokes the event.
///
/// The that is/has been replaced.
/// The new to be replaced.
public virtual void OnTitleChanged (ustring oldTitle, ustring newTitle)
{
var args = new TitleEventArgs (oldTitle, newTitle);
TitleChanged?.Invoke (args);
}
///
/// Event fired after the has been changed.
///
public event Action TitleChanged;
}
}