//
// 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)
{
SetInitialProperties (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 ()
{
SetInitialProperties (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 SetInitialProperties (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) {
// TODO: v2 this is a hack until Border gets refactored
Border = new Border () {
BorderStyle = DefaultBorderStyle,
PaddingThickness = new Thickness (padding),
};
} else {
Border = border;
}
BorderFrame.Thickness = new Thickness (1);
BorderFrame.BorderStyle = Border.BorderStyle;
BorderFrame.ColorScheme = ColorScheme;
BorderFrame.Data = "BorderFrame";
// TODO: Hack until Border is refactored
Padding.Thickness = Border.PaddingThickness ?? Padding.Thickness;
}
public override void BeginInit ()
{
base.BeginInit ();
}
///
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);
}
///
/// 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;
}
}