From 65c37edb5bce3ddb2e8afac92eb877a11edd99ae Mon Sep 17 00:00:00 2001 From: tznind Date: Mon, 22 May 2023 19:44:50 +0100 Subject: [PATCH 1/9] Move all public nested classes out into own files --- Terminal.Gui/Configuration/AppScope.cs | 58 +++-- Terminal.Gui/Configuration/ConfigProperty.cs | 97 ++++++++ .../Configuration/ConfigurationManager.cs | 116 +-------- Terminal.Gui/Configuration/Scope.cs | 229 ++++-------------- .../Configuration/ScopeJsonConverter.cs | 140 +++++++++++ .../SerializableConfigurationProperty.cs | 28 +++ Terminal.Gui/Configuration/SettingsScope.cs | 185 +++++++------- .../CursesDriver/CursesDriver.cs | 6 +- .../CursesDriver/CursesWindow.cs | 162 +++++++++++++ .../ConsoleDrivers/CursesDriver/binding.cs | 6 +- .../ConsoleDrivers/CursesDriver/handles.cs | 125 ---------- .../ConsoleDrivers/FakeDriver/FakeConsole.cs | 3 + .../ConsoleDrivers/FakeDriver/FakeDriver.cs | 22 +- .../FakeDriver/FakeDriverBehaviors.cs | 26 ++ Terminal.Gui/GlobalSuppressions.cs | 8 + Terminal.Gui/MainLoop.cs | 15 +- Terminal.Gui/Timeout.cs | 24 ++ Terminal.Gui/Views/FileDialog.cs | 2 +- Terminal.Gui/Views/GraphView/Annotations.cs | 26 +- Terminal.Gui/Views/GraphView/Bar.cs | 40 +++ Terminal.Gui/Views/GraphView/LineF.cs | 27 +++ Terminal.Gui/Views/GraphView/Series.cs | 43 +--- .../Views/TableView/CellColorGetterArgs.cs | 50 ++++ .../Views/TableView/ListColumnStyle.cs | 19 ++ .../Views/TableView/ListTableSource.cs | 20 +- .../Views/TableView/RowColorGetterArgs.cs | 25 ++ Terminal.Gui/Views/TableView/TableView.cs | 73 +----- Terminal.Gui/Views/Tile.cs | 95 ++++++++ Terminal.Gui/Views/TileView.cs | 93 +------ Terminal.Gui/Views/Wizard/Wizard.cs | 212 +--------------- Terminal.Gui/Views/Wizard/WizardStep.cs | 209 ++++++++++++++++ UICatalog/Scenarios/ConfigurationEditor.cs | 2 +- UICatalog/Scenarios/GraphViewExample.cs | 128 +++++----- UICatalog/Scenarios/ListColumns.cs | 2 +- UICatalog/Scenarios/WizardAsView.cs | 6 +- UICatalog/Scenarios/Wizards.cs | 12 +- UnitTests/Application/MainLoopTests.cs | 2 +- UnitTests/Dialogs/WizardTests.cs | 38 +-- UnitTests/Views/GraphViewTests.cs | 10 +- UnitTests/Views/TableViewTests.cs | 2 +- 40 files changed, 1244 insertions(+), 1142 deletions(-) create mode 100644 Terminal.Gui/Configuration/ConfigProperty.cs create mode 100644 Terminal.Gui/Configuration/ScopeJsonConverter.cs create mode 100644 Terminal.Gui/Configuration/SerializableConfigurationProperty.cs create mode 100644 Terminal.Gui/ConsoleDrivers/CursesDriver/CursesWindow.cs create mode 100644 Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriverBehaviors.cs create mode 100644 Terminal.Gui/GlobalSuppressions.cs create mode 100644 Terminal.Gui/Timeout.cs create mode 100644 Terminal.Gui/Views/GraphView/Bar.cs create mode 100644 Terminal.Gui/Views/GraphView/LineF.cs create mode 100644 Terminal.Gui/Views/TableView/CellColorGetterArgs.cs create mode 100644 Terminal.Gui/Views/TableView/ListColumnStyle.cs create mode 100644 Terminal.Gui/Views/TableView/RowColorGetterArgs.cs create mode 100644 Terminal.Gui/Views/Tile.cs create mode 100644 Terminal.Gui/Views/Wizard/WizardStep.cs diff --git a/Terminal.Gui/Configuration/AppScope.cs b/Terminal.Gui/Configuration/AppScope.cs index da76d3d4d5..7d8586a4fa 100644 --- a/Terminal.Gui/Configuration/AppScope.cs +++ b/Terminal.Gui/Configuration/AppScope.cs @@ -11,35 +11,33 @@ namespace Terminal.Gui { - public static partial class ConfigurationManager { - /// - /// The class for application-defined configuration settings. - /// - /// - /// - /// - /// - /// Use the attribute to mark properties that should be serialized as part - /// of application-defined configuration settings. - /// - /// - /// public class MyAppSettings { - /// [SerializableConfigurationProperty (Scope = typeof (AppScope))] - /// public static bool? MyProperty { get; set; } = true; - /// } - /// - /// - /// THe resultant Json will look like this: - /// - /// - /// "AppSettings": { - /// "MyAppSettings.MyProperty": true, - /// "UICatalog.ShowStatusBar": true - /// }, - /// - /// - [JsonConverter (typeof (ScopeJsonConverter))] - public class AppScope : Scope { - } + /// + /// The class for application-defined configuration settings. + /// + /// + /// + /// + /// + /// Use the attribute to mark properties that should be serialized as part + /// of application-defined configuration settings. + /// + /// + /// public class MyAppSettings { + /// [SerializableConfigurationProperty (Scope = typeof (AppScope))] + /// public static bool? MyProperty { get; set; } = true; + /// } + /// + /// + /// THe resultant Json will look like this: + /// + /// + /// "AppSettings": { + /// "MyAppSettings.MyProperty": true, + /// "UICatalog.ShowStatusBar": true + /// }, + /// + /// + [JsonConverter (typeof (ScopeJsonConverter))] + public class AppScope : Scope { } } \ No newline at end of file diff --git a/Terminal.Gui/Configuration/ConfigProperty.cs b/Terminal.Gui/Configuration/ConfigProperty.cs new file mode 100644 index 0000000000..2f0617c384 --- /dev/null +++ b/Terminal.Gui/Configuration/ConfigProperty.cs @@ -0,0 +1,97 @@ +using System; +using System.Reflection; +using System.Text.Json.Serialization; + +#nullable enable + +namespace Terminal.Gui; + +/// +/// Holds a property's value and the that allows +/// to get and set the property's value. +/// +/// +/// Configuration properties must be and +/// and have the +/// attribute. If the type of the property requires specialized JSON serialization, +/// a must be provided using +/// the attribute. +/// +public class ConfigProperty { + private object? propertyValue; + + /// + /// Describes the property. + /// + public PropertyInfo? PropertyInfo { get; set; } + + /// + /// Helper to get either the Json property named (specified by [JsonPropertyName(name)] + /// or the actual property name. + /// + /// + /// + public static string GetJsonPropertyName (PropertyInfo pi) + { + var jpna = pi.GetCustomAttribute (typeof (JsonPropertyNameAttribute)) as JsonPropertyNameAttribute; + return jpna?.Name ?? pi.Name; + } + + /// + /// Holds the property's value as it was either read from the class's implementation or from a config file. + /// If the property has not been set (e.g. because no configuration file specified a value), + /// this will be . + /// + /// + /// On , performs a sparse-copy of the new value to the existing value (only copies elements of + /// the object that are non-null). + /// + public object? PropertyValue { + get => propertyValue; + set { + propertyValue = value; + } + } + + internal object? UpdateValueFrom (object source) + { + if (source == null) { + return PropertyValue; + } + + var ut = Nullable.GetUnderlyingType (PropertyInfo!.PropertyType); + if (source.GetType () != PropertyInfo!.PropertyType && (ut != null && source.GetType () != ut)) { + throw new ArgumentException ($"The source object ({PropertyInfo!.DeclaringType}.{PropertyInfo!.Name}) is not of type {PropertyInfo!.PropertyType}."); + } + if (PropertyValue != null && source != null) { + PropertyValue = ConfigurationManager.DeepMemberwiseCopy (source, PropertyValue); + } else { + PropertyValue = source; + } + + return PropertyValue; + } + + /// + /// Retrieves (using reflection) the value of the static property described in + /// into . + /// + /// + public object? RetrieveValue () + { + return PropertyValue = PropertyInfo!.GetValue (null); + } + + /// + /// Applies the to the property described by . + /// + /// + public bool Apply () + { + if (PropertyValue != null) { + PropertyInfo?.SetValue (null, ConfigurationManager.DeepMemberwiseCopy (PropertyValue, PropertyInfo?.GetValue (null))); + } + return PropertyValue != null; + } + +} diff --git a/Terminal.Gui/Configuration/ConfigurationManager.cs b/Terminal.Gui/Configuration/ConfigurationManager.cs index 9055405873..7a47fc70b8 100644 --- a/Terminal.Gui/Configuration/ConfigurationManager.cs +++ b/Terminal.Gui/Configuration/ConfigurationManager.cs @@ -69,118 +69,6 @@ public static partial class ConfigurationManager { }, }; - /// - /// An attribute that can be applied to a property to indicate that it should included in the configuration file. - /// - /// - /// [SerializableConfigurationProperty(Scope = typeof(Configuration.ThemeManager.ThemeScope)), JsonConverter (typeof (JsonStringEnumConverter))] - /// public static LineStyle DefaultBorderStyle { - /// ... - /// - [AttributeUsage (AttributeTargets.Property, AllowMultiple = false, Inherited = false)] - public class SerializableConfigurationProperty : System.Attribute { - /// - /// Specifies the scope of the property. - /// - public Type? Scope { get; set; } - - /// - /// If , the property will be serialized to the configuration file using only the property name - /// as the key. If , the property will be serialized to the configuration file using the - /// property name pre-pended with the classname (e.g. Application.UseSystemConsole). - /// - public bool OmitClassName { get; set; } - } - - /// - /// Holds a property's value and the that allows - /// to get and set the property's value. - /// - /// - /// Configuration properties must be and - /// and have the - /// attribute. If the type of the property requires specialized JSON serialization, - /// a must be provided using - /// the attribute. - /// - public class ConfigProperty { - private object? propertyValue; - - /// - /// Describes the property. - /// - public PropertyInfo? PropertyInfo { get; set; } - - /// - /// Helper to get either the Json property named (specified by [JsonPropertyName(name)] - /// or the actual property name. - /// - /// - /// - public static string GetJsonPropertyName (PropertyInfo pi) - { - var jpna = pi.GetCustomAttribute (typeof (JsonPropertyNameAttribute)) as JsonPropertyNameAttribute; - return jpna?.Name ?? pi.Name; - } - - /// - /// Holds the property's value as it was either read from the class's implementation or from a config file. - /// If the property has not been set (e.g. because no configuration file specified a value), - /// this will be . - /// - /// - /// On , performs a sparse-copy of the new value to the existing value (only copies elements of - /// the object that are non-null). - /// - public object? PropertyValue { - get => propertyValue; - set { - propertyValue = value; - } - } - - internal object? UpdateValueFrom (object source) - { - if (source == null) { - return PropertyValue; - } - - var ut = Nullable.GetUnderlyingType (PropertyInfo!.PropertyType); - if (source.GetType () != PropertyInfo!.PropertyType && (ut != null && source.GetType () != ut)) { - throw new ArgumentException ($"The source object ({PropertyInfo!.DeclaringType}.{PropertyInfo!.Name}) is not of type {PropertyInfo!.PropertyType}."); - } - if (PropertyValue != null && source != null) { - PropertyValue = DeepMemberwiseCopy (source, PropertyValue); - } else { - PropertyValue = source; - } - - return PropertyValue; - } - - /// - /// Retrieves (using reflection) the value of the static property described in - /// into . - /// - /// - public object? RetrieveValue () - { - return PropertyValue = PropertyInfo!.GetValue (null); - } - - /// - /// Applies the to the property described by . - /// - /// - public bool Apply () - { - if (PropertyValue != null) { - PropertyInfo?.SetValue (null, DeepMemberwiseCopy (PropertyValue, PropertyInfo?.GetValue (null))); - } - return PropertyValue != null; - } - } - /// /// A dictionary of all properties in the Terminal.Gui project that are decorated with the attribute. /// The keys are the property names pre-pended with the class that implements the property (e.g. Application.UseSystemConsole). @@ -190,7 +78,7 @@ public bool Apply () /// /// Is until is called. /// - private static Dictionary? _allConfigProperties; + internal static Dictionary? _allConfigProperties; /// /// The backing property for . @@ -319,7 +207,7 @@ internal static Stream ToStream () internal static StringBuilder jsonErrors = new StringBuilder (); - private static void AddJsonError (string error) + internal static void AddJsonError (string error) { Debug.WriteLine ($"ConfigurationManager: {error}"); jsonErrors.AppendLine (error); diff --git a/Terminal.Gui/Configuration/Scope.cs b/Terminal.Gui/Configuration/Scope.cs index 245153dd2a..919d5bced8 100644 --- a/Terminal.Gui/Configuration/Scope.cs +++ b/Terminal.Gui/Configuration/Scope.cs @@ -3,209 +3,74 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; -using System.Text.Json; -using System.Text.Json.Serialization; using static Terminal.Gui.ConfigurationManager; #nullable enable namespace Terminal.Gui { - public static partial class ConfigurationManager { + /// + /// Defines a configuration settings scope. Classes that inherit from this abstract class can be used to define + /// scopes for configuration settings. Each scope is a JSON object that contains a set of configuration settings. + /// + public class Scope : Dictionary { //, IScope> { /// - /// Defines a configuration settings scope. Classes that inherit from this abstract class can be used to define - /// scopes for configuration settings. Each scope is a JSON object that contains a set of configuration settings. + /// Crates a new instance. /// - public class Scope : Dictionary { //, IScope> { - /// - /// Crates a new instance. - /// - public Scope () : base (StringComparer.InvariantCultureIgnoreCase) - { - foreach (var p in GetScopeProperties ()) { - Add (p.Key, new ConfigProperty () { PropertyInfo = p.Value.PropertyInfo, PropertyValue = null }); - } - } - - private IEnumerable> GetScopeProperties () - { - return ConfigurationManager._allConfigProperties!.Where (cp => - (cp.Value.PropertyInfo?.GetCustomAttribute (typeof (SerializableConfigurationProperty)) - as SerializableConfigurationProperty)?.Scope == GetType ()); - } - - /// - /// Updates this instance from the specified source scope. - /// - /// - /// The updated scope (this). - public Scope? Update (Scope source) - { - foreach (var prop in source) { - if (ContainsKey (prop.Key)) - this [prop.Key].PropertyValue = this [prop.Key].UpdateValueFrom (prop.Value.PropertyValue!); - else { - this [prop.Key].PropertyValue = prop.Value.PropertyValue; - } - } - return this; + public Scope () : base (StringComparer.InvariantCultureIgnoreCase) + { + foreach (var p in GetScopeProperties ()) { + Add (p.Key, new ConfigProperty () { PropertyInfo = p.Value.PropertyInfo, PropertyValue = null }); } + } - /// - /// Retrieves the values of the properties of this scope from their corresponding static properties. - /// - public void RetrieveValues () - { - foreach (var p in this.Where (cp => cp.Value.PropertyInfo != null)) { - p.Value.RetrieveValue (); - } - } + private IEnumerable> GetScopeProperties () + { + return ConfigurationManager._allConfigProperties!.Where (cp => + (cp.Value.PropertyInfo?.GetCustomAttribute (typeof (SerializableConfigurationProperty)) + as SerializableConfigurationProperty)?.Scope == GetType ()); + } - /// - /// Applies the values of the properties of this scope to their corresponding static properties. - /// - /// - internal virtual bool Apply () - { - bool set = false; - foreach (var p in this.Where (t => t.Value != null && t.Value.PropertyValue != null)) { - if (p.Value.Apply ()) { - set = true; - } + /// + /// Updates this instance from the specified source scope. + /// + /// + /// The updated scope (this). + public Scope? Update (Scope source) + { + foreach (var prop in source) { + if (ContainsKey (prop.Key)) + this [prop.Key].PropertyValue = this [prop.Key].UpdateValueFrom (prop.Value.PropertyValue!); + else { + this [prop.Key].PropertyValue = prop.Value.PropertyValue; } - return set; } + return this; } /// - /// Converts instances to/from JSON. Does all the heavy lifting of reading/writing - /// config data to/from JSON documents. + /// Retrieves the values of the properties of this scope from their corresponding static properties. /// - /// - class ScopeJsonConverter : JsonConverter where scopeT : Scope { - // See: https://stackoverflow.com/questions/60830084/how-to-pass-an-argument-by-reference-using-reflection - internal abstract class ReadHelper { - public abstract object? Read (ref Utf8JsonReader reader, Type type, JsonSerializerOptions options); - } - - internal class ReadHelper : ReadHelper { - private readonly ReadDelegate _readDelegate; - private delegate converterT ReadDelegate (ref Utf8JsonReader reader, Type type, JsonSerializerOptions options); - public ReadHelper (object converter) - => _readDelegate = (ReadDelegate)Delegate.CreateDelegate (typeof (ReadDelegate), converter, "Read"); - public override object? Read (ref Utf8JsonReader reader, Type type, JsonSerializerOptions options) - => _readDelegate.Invoke (ref reader, type, options); - } - - public override scopeT Read (ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - if (reader.TokenType != JsonTokenType.StartObject) { - throw new JsonException ($"Expected a JSON object (\"{{ \"propName\" : ... }}\"), but got \"{reader.TokenType}\"."); - } - - var scope = (scopeT)Activator.CreateInstance (typeof (scopeT))!; - while (reader.Read ()) { - if (reader.TokenType == JsonTokenType.EndObject) { - return scope!; - } - if (reader.TokenType != JsonTokenType.PropertyName) { - throw new JsonException ($"Expected a JSON property name, but got \"{reader.TokenType}\"."); - } - var propertyName = reader.GetString (); - reader.Read (); - - if (propertyName != null && scope!.TryGetValue (propertyName, out var configProp)) { - // This property name was found in the Scope's ScopeProperties dictionary - // Figure out if it needs a JsonConverter and if so, create one - var propertyType = configProp?.PropertyInfo?.PropertyType!; - if (configProp?.PropertyInfo?.GetCustomAttribute (typeof (JsonConverterAttribute)) is JsonConverterAttribute jca) { - var converter = Activator.CreateInstance (jca.ConverterType!)!; - if (converter.GetType ().BaseType == typeof (JsonConverterFactory)) { - var factory = (JsonConverterFactory)converter; - if (propertyType != null && factory.CanConvert (propertyType)) { - converter = factory.CreateConverter (propertyType, options); - } - } - var readHelper = Activator.CreateInstance ((Type?)typeof (ReadHelper<>).MakeGenericType (typeof (scopeT), propertyType!)!, converter) as ReadHelper; - try { - scope! [propertyName].PropertyValue = readHelper?.Read (ref reader, propertyType!, options); - } catch (NotSupportedException e) { - throw new JsonException ($"Error reading property \"{propertyName}\" of type \"{propertyType?.Name}\".", e); - } - } else { - try { - scope! [propertyName].PropertyValue = JsonSerializer.Deserialize (ref reader, propertyType!, options); - } catch (Exception ex) { - System.Diagnostics.Debug.WriteLine ($"scopeT Read: {ex}"); - } - } - } else { - // It is not a config property. Maybe it's just a property on the Scope with [JsonInclude] - // like ScopeSettings.$schema... - var property = scope!.GetType ().GetProperties ().Where (p => { - var jia = p.GetCustomAttribute (typeof (JsonIncludeAttribute)) as JsonIncludeAttribute; - if (jia != null) { - var jpna = p.GetCustomAttribute (typeof (JsonPropertyNameAttribute)) as JsonPropertyNameAttribute; - if (jpna?.Name == propertyName) { - // Bit of a hack, modifying propertyName in an enumerator... - propertyName = p.Name; - return true; - } - - return p.Name == propertyName; - } - return false; - }).FirstOrDefault (); - - if (property != null) { - var prop = scope.GetType ().GetProperty (propertyName!)!; - prop.SetValue (scope, JsonSerializer.Deserialize (ref reader, prop.PropertyType, options)); - } else { - // Unknown property - throw new JsonException ($"Unknown property name \"{propertyName}\"."); - } - } - } - throw new JsonException (); + public void RetrieveValues () + { + foreach (var p in this.Where (cp => cp.Value.PropertyInfo != null)) { + p.Value.RetrieveValue (); } + } - public override void Write (Utf8JsonWriter writer, scopeT scope, JsonSerializerOptions options) - { - writer.WriteStartObject (); - - var properties = scope!.GetType ().GetProperties ().Where (p => p.GetCustomAttribute (typeof (JsonIncludeAttribute)) != null); - foreach (var p in properties) { - writer.WritePropertyName (ConfigProperty.GetJsonPropertyName (p)); - JsonSerializer.Serialize (writer, scope.GetType ().GetProperty (p.Name)?.GetValue (scope), options); - } - - foreach (var p in from p in scope - .Where (cp => - cp.Value.PropertyInfo?.GetCustomAttribute (typeof (SerializableConfigurationProperty)) is - SerializableConfigurationProperty scp && scp?.Scope == typeof (scopeT)) - where p.Value.PropertyValue != null - select p) { - - writer.WritePropertyName (p.Key); - var propertyType = p.Value.PropertyInfo?.PropertyType; - - if (propertyType != null && p.Value.PropertyInfo?.GetCustomAttribute (typeof (JsonConverterAttribute)) is JsonConverterAttribute jca) { - var converter = Activator.CreateInstance (jca.ConverterType!)!; - if (converter.GetType ().BaseType == typeof (JsonConverterFactory)) { - var factory = (JsonConverterFactory)converter; - if (factory.CanConvert (propertyType)) { - converter = factory.CreateConverter (propertyType, options)!; - } - } - if (p.Value.PropertyValue != null) { - converter.GetType ().GetMethod ("Write")?.Invoke (converter, new object [] { writer, p.Value.PropertyValue, options }); - } - } else { - JsonSerializer.Serialize (writer, p.Value.PropertyValue, options); - } + /// + /// Applies the values of the properties of this scope to their corresponding static properties. + /// + /// + internal virtual bool Apply () + { + bool set = false; + foreach (var p in this.Where (t => t.Value != null && t.Value.PropertyValue != null)) { + if (p.Value.Apply ()) { + set = true; } - writer.WriteEndObject (); } + return set; } } } diff --git a/Terminal.Gui/Configuration/ScopeJsonConverter.cs b/Terminal.Gui/Configuration/ScopeJsonConverter.cs new file mode 100644 index 0000000000..edd5419066 --- /dev/null +++ b/Terminal.Gui/Configuration/ScopeJsonConverter.cs @@ -0,0 +1,140 @@ +using System; +using System.Linq; +using System.Reflection; +using System.Text.Json; +using System.Text.Json.Serialization; + +#nullable enable + +namespace Terminal.Gui { + /// + /// Converts instances to/from JSON. Does all the heavy lifting of reading/writing + /// config data to/from JSON documents. + /// + /// + internal class ScopeJsonConverter : JsonConverter where scopeT : Scope { + // See: https://stackoverflow.com/questions/60830084/how-to-pass-an-argument-by-reference-using-reflection + internal abstract class ReadHelper { + public abstract object? Read (ref Utf8JsonReader reader, Type type, JsonSerializerOptions options); + } + + internal class ReadHelper : ReadHelper { + private readonly ReadDelegate _readDelegate; + private delegate converterT ReadDelegate (ref Utf8JsonReader reader, Type type, JsonSerializerOptions options); + public ReadHelper (object converter) + => _readDelegate = (ReadDelegate)Delegate.CreateDelegate (typeof (ReadDelegate), converter, "Read"); + public override object? Read (ref Utf8JsonReader reader, Type type, JsonSerializerOptions options) + => _readDelegate.Invoke (ref reader, type, options); + } + + public override scopeT Read (ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType != JsonTokenType.StartObject) { + throw new JsonException ($"Expected a JSON object (\"{{ \"propName\" : ... }}\"), but got \"{reader.TokenType}\"."); + } + + var scope = (scopeT)Activator.CreateInstance (typeof (scopeT))!; + while (reader.Read ()) { + if (reader.TokenType == JsonTokenType.EndObject) { + return scope!; + } + if (reader.TokenType != JsonTokenType.PropertyName) { + throw new JsonException ($"Expected a JSON property name, but got \"{reader.TokenType}\"."); + } + var propertyName = reader.GetString (); + reader.Read (); + + if (propertyName != null && scope!.TryGetValue (propertyName, out var configProp)) { + // This property name was found in the Scope's ScopeProperties dictionary + // Figure out if it needs a JsonConverter and if so, create one + var propertyType = configProp?.PropertyInfo?.PropertyType!; + if (configProp?.PropertyInfo?.GetCustomAttribute (typeof (JsonConverterAttribute)) is JsonConverterAttribute jca) { + var converter = Activator.CreateInstance (jca.ConverterType!)!; + if (converter.GetType ().BaseType == typeof (JsonConverterFactory)) { + var factory = (JsonConverterFactory)converter; + if (propertyType != null && factory.CanConvert (propertyType)) { + converter = factory.CreateConverter (propertyType, options); + } + } + var readHelper = Activator.CreateInstance ((Type?)typeof (ReadHelper<>).MakeGenericType (typeof (scopeT), propertyType!)!, converter) as ReadHelper; + try { + scope! [propertyName].PropertyValue = readHelper?.Read (ref reader, propertyType!, options); + } catch (NotSupportedException e) { + throw new JsonException ($"Error reading property \"{propertyName}\" of type \"{propertyType?.Name}\".", e); + } + } else { + try { + scope! [propertyName].PropertyValue = JsonSerializer.Deserialize (ref reader, propertyType!, options); + } catch (Exception ex) { + System.Diagnostics.Debug.WriteLine ($"scopeT Read: {ex}"); + } + } + } else { + // It is not a config property. Maybe it's just a property on the Scope with [JsonInclude] + // like ScopeSettings.$schema... + var property = scope!.GetType ().GetProperties ().Where (p => { + var jia = p.GetCustomAttribute (typeof (JsonIncludeAttribute)) as JsonIncludeAttribute; + if (jia != null) { + var jpna = p.GetCustomAttribute (typeof (JsonPropertyNameAttribute)) as JsonPropertyNameAttribute; + if (jpna?.Name == propertyName) { + // Bit of a hack, modifying propertyName in an enumerator... + propertyName = p.Name; + return true; + } + + return p.Name == propertyName; + } + return false; + }).FirstOrDefault (); + + if (property != null) { + var prop = scope.GetType ().GetProperty (propertyName!)!; + prop.SetValue (scope, JsonSerializer.Deserialize (ref reader, prop.PropertyType, options)); + } else { + // Unknown property + throw new JsonException ($"Unknown property name \"{propertyName}\"."); + } + } + } + throw new JsonException (); + } + + public override void Write (Utf8JsonWriter writer, scopeT scope, JsonSerializerOptions options) + { + writer.WriteStartObject (); + + var properties = scope!.GetType ().GetProperties ().Where (p => p.GetCustomAttribute (typeof (JsonIncludeAttribute)) != null); + foreach (var p in properties) { + writer.WritePropertyName (ConfigProperty.GetJsonPropertyName (p)); + JsonSerializer.Serialize (writer, scope.GetType ().GetProperty (p.Name)?.GetValue (scope), options); + } + + foreach (var p in from p in scope + .Where (cp => + cp.Value.PropertyInfo?.GetCustomAttribute (typeof (SerializableConfigurationProperty)) is + SerializableConfigurationProperty scp && scp?.Scope == typeof (scopeT)) + where p.Value.PropertyValue != null + select p) { + + writer.WritePropertyName (p.Key); + var propertyType = p.Value.PropertyInfo?.PropertyType; + + if (propertyType != null && p.Value.PropertyInfo?.GetCustomAttribute (typeof (JsonConverterAttribute)) is JsonConverterAttribute jca) { + var converter = Activator.CreateInstance (jca.ConverterType!)!; + if (converter.GetType ().BaseType == typeof (JsonConverterFactory)) { + var factory = (JsonConverterFactory)converter; + if (factory.CanConvert (propertyType)) { + converter = factory.CreateConverter (propertyType, options)!; + } + } + if (p.Value.PropertyValue != null) { + converter.GetType ().GetMethod ("Write")?.Invoke (converter, new object [] { writer, p.Value.PropertyValue, options }); + } + } else { + JsonSerializer.Serialize (writer, p.Value.PropertyValue, options); + } + } + writer.WriteEndObject (); + } + } +} diff --git a/Terminal.Gui/Configuration/SerializableConfigurationProperty.cs b/Terminal.Gui/Configuration/SerializableConfigurationProperty.cs new file mode 100644 index 0000000000..842b2cc7c7 --- /dev/null +++ b/Terminal.Gui/Configuration/SerializableConfigurationProperty.cs @@ -0,0 +1,28 @@ +using System; + +#nullable enable + +namespace Terminal.Gui; + +/// +/// An attribute that can be applied to a property to indicate that it should included in the configuration file. +/// +/// +/// [SerializableConfigurationProperty(Scope = typeof(Configuration.ThemeManager.ThemeScope)), JsonConverter (typeof (JsonStringEnumConverter))] +/// public static LineStyle DefaultBorderStyle { +/// ... +/// +[AttributeUsage (AttributeTargets.Property, AllowMultiple = false, Inherited = false)] +public class SerializableConfigurationProperty : System.Attribute { + /// + /// Specifies the scope of the property. + /// + public Type? Scope { get; set; } + + /// + /// If , the property will be serialized to the configuration file using only the property name + /// as the key. If , the property will be serialized to the configuration file using the + /// property name pre-pended with the classname (e.g. Application.UseSystemConsole). + /// + public bool OmitClassName { get; set; } +} \ No newline at end of file diff --git a/Terminal.Gui/Configuration/SettingsScope.cs b/Terminal.Gui/Configuration/SettingsScope.cs index 2bf7288c33..857cf9e081 100644 --- a/Terminal.Gui/Configuration/SettingsScope.cs +++ b/Terminal.Gui/Configuration/SettingsScope.cs @@ -9,112 +9,111 @@ #nullable enable namespace Terminal.Gui { - public static partial class ConfigurationManager { + /// + /// The root object of Terminal.Gui configuration settings / JSON schema. Contains only properties + /// attributed with . + /// + /// + /// { + /// "$schema" : "https://gui-cs.github.io/Terminal.Gui/schemas/tui-config-schema.json", + /// "Application.UseSystemConsole" : true, + /// "Theme" : "Default", + /// "Themes": { + /// }, + /// }, + /// + /// + /// + [JsonConverter (typeof (ScopeJsonConverter))] + public class SettingsScope : Scope { /// - /// The root object of Terminal.Gui configuration settings / JSON schema. Contains only properties - /// attributed with . + /// Points to our JSON schema. /// - /// - /// { - /// "$schema" : "https://gui-cs.github.io/Terminal.Gui/schemas/tui-config-schema.json", - /// "Application.UseSystemConsole" : true, - /// "Theme" : "Default", - /// "Themes": { - /// }, - /// }, - /// - /// - /// - [JsonConverter (typeof (ScopeJsonConverter))] - public class SettingsScope : Scope { - /// - /// Points to our JSON schema. - /// - [JsonInclude, JsonPropertyName ("$schema")] - public string Schema { get; set; } = "https://gui-cs.github.io/Terminal.Gui/schemas/tui-config-schema.json"; + [JsonInclude, JsonPropertyName ("$schema")] + public string Schema { get; set; } = "https://gui-cs.github.io/Terminal.Gui/schemas/tui-config-schema.json"; - /// - /// The list of paths to the configuration files. - /// - public List Sources = new List (); + /// + /// The list of paths to the configuration files. + /// + public List Sources = new List (); - /// - /// Updates the with the settings in a JSON string. - /// - /// Json document to update the settings with. - /// The source (filename/resource name) the Json document was read from. - public SettingsScope? Update (Stream stream, string source) - { - // Update the existing settings with the new settings. - try { - Update (JsonSerializer.Deserialize (stream, _serializerOptions)!); - OnUpdated (); - Debug.WriteLine ($"ConfigurationManager: Read configuration from \"{source}\""); - Sources.Add (source); - return this; - } catch (JsonException e) { - if (ThrowOnJsonErrors ?? false) { - throw; - } else { - AddJsonError ($"Error deserializing {source}: {e.Message}"); - } - } + /// + /// Updates the with the settings in a JSON string. + /// + /// Json document to update the settings with. + /// The source (filename/resource name) the Json document was read from. + public SettingsScope? Update (Stream stream, string source) + { + // Update the existing settings with the new settings. + try { + Update (JsonSerializer.Deserialize (stream, ConfigurationManager._serializerOptions)!); + ConfigurationManager.OnUpdated (); + Debug.WriteLine ($"ConfigurationManager: Read configuration from \"{source}\""); + Sources.Add (source); return this; - } - - /// - /// Updates the with the settings in a JSON file. - /// - /// - public SettingsScope? Update (string filePath) - { - var realPath = filePath.Replace("~", Environment.GetFolderPath (Environment.SpecialFolder.UserProfile)); - if (!File.Exists (realPath)) { - Debug.WriteLine ($"ConfigurationManager: Configuration file \"{realPath}\" does not exist."); - Sources.Add (filePath); - return this; + } catch (JsonException e) { + if (ConfigurationManager.ThrowOnJsonErrors ?? false) { + throw; + } else { + ConfigurationManager.AddJsonError ($"Error deserializing {source}: {e.Message}"); } + } + return this; + } - var stream = File.OpenRead (realPath); - return Update (stream, filePath); + /// + /// Updates the with the settings in a JSON file. + /// + /// + public SettingsScope? Update (string filePath) + { + var realPath = filePath.Replace ("~", Environment.GetFolderPath (Environment.SpecialFolder.UserProfile)); + if (!File.Exists (realPath)) { + Debug.WriteLine ($"ConfigurationManager: Configuration file \"{realPath}\" does not exist."); + Sources.Add (filePath); + return this; } - /// - /// Updates the with the settings from a Json resource. - /// - /// - /// - public SettingsScope? UpdateFromResource (Assembly assembly, string resourceName) - { - if (resourceName == null || string.IsNullOrEmpty (resourceName)) { - Debug.WriteLine ($"ConfigurationManager: Resource \"{resourceName}\" does not exist in \"{assembly.GetName ().Name}\"."); - return this; - } - - using Stream? stream = assembly.GetManifestResourceStream (resourceName)!; - if (stream == null) { - Debug.WriteLine ($"ConfigurationManager: Failed to read resource \"{resourceName}\" from \"{assembly.GetName ().Name}\"."); - return this; - } + var stream = File.OpenRead (realPath); + return Update (stream, filePath); + } - return Update (stream, $"resource://[{assembly.GetName().Name}]/{resourceName}"); + /// + /// Updates the with the settings from a Json resource. + /// + /// + /// + public SettingsScope? UpdateFromResource (Assembly assembly, string resourceName) + { + if (resourceName == null || string.IsNullOrEmpty (resourceName)) { + Debug.WriteLine ($"ConfigurationManager: Resource \"{resourceName}\" does not exist in \"{assembly.GetName ().Name}\"."); + return this; } - /// - /// Updates the with the settings in a JSON string. - /// - /// Json document to update the settings with. - /// The source (filename/resource name) the Json document was read from. - public SettingsScope? Update (string json, string source) - { - var stream = new MemoryStream (); - var writer = new StreamWriter (stream); - writer.Write (json); - writer.Flush (); - stream.Position = 0; - - return Update (stream, source); + using Stream? stream = assembly.GetManifestResourceStream (resourceName)!; + if (stream == null) { + Debug.WriteLine ($"ConfigurationManager: Failed to read resource \"{resourceName}\" from \"{assembly.GetName ().Name}\"."); + return this; } + + return Update (stream, $"resource://[{assembly.GetName ().Name}]/{resourceName}"); + } + + /// + /// Updates the with the settings in a JSON string. + /// + /// Json document to update the settings with. + /// The source (filename/resource name) the Json document was read from. + public SettingsScope? Update (string json, string source) + { + var stream = new MemoryStream (); + var writer = new StreamWriter (stream); + writer.Write (json); + writer.Flush (); + stream.Position = 0; + + return Update (stream, source); } } + } diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs index eaba76d7e4..107a1f27b0 100644 --- a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs @@ -180,7 +180,7 @@ public override void SetAttribute (Attribute c) Curses.attrset (CurrentAttribute); } - public Curses.Window window; + public CursesWindow window; //static short last_color_pair = 16; @@ -592,7 +592,7 @@ public override void Init (Action terminalResized) Curses.raw (); Curses.noecho (); - Curses.Window.Standard.keypad (true); + CursesWindow.Standard.keypad (true); TerminalResized = terminalResized; StartReportingMouseMoves (); @@ -765,7 +765,7 @@ public override void Suspend () { StopReportingMouseMoves (); Platform.Suspend (); - Curses.Window.Standard.redrawwin (); + CursesWindow.Standard.redrawwin (); Curses.refresh (); StartReportingMouseMoves (); } diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesWindow.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesWindow.cs new file mode 100644 index 0000000000..b9975e232a --- /dev/null +++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesWindow.cs @@ -0,0 +1,162 @@ +// +// handles.cs: OO wrappers for some curses objects +// +// Authors: +// Miguel de Icaza (miguel.de.icaza@gmail.com) +// +// Copyright (C) 2007 Novell (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +using System; + +namespace Unix.Terminal { +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + + public class CursesWindow { + public readonly IntPtr Handle; + static CursesWindow curscr; + static CursesWindow stdscr; + + static CursesWindow () + { + Curses.initscr (); + stdscr = new CursesWindow (Curses.console_sharp_get_stdscr ()); + curscr = new CursesWindow (Curses.console_sharp_get_curscr ()); + } + + internal CursesWindow (IntPtr handle) + { + Handle = handle; + } + + static public CursesWindow Standard { + get { + return stdscr; + } + } + + static public CursesWindow Current { + get { + return curscr; + } + } + + public int wtimeout (int delay) + { + return Curses.wtimeout (Handle, delay); + } + + public int notimeout (bool bf) + { + return Curses.notimeout (Handle, bf); + } + + public int keypad (bool bf) + { + return Curses.keypad (Handle, bf); + } + + public int meta (bool bf) + { + return Curses.meta (Handle, bf); + } + + public int intrflush (bool bf) + { + return Curses.intrflush (Handle, bf); + } + + public int clearok (bool bf) + { + return Curses.clearok (Handle, bf); + } + + public int idlok (bool bf) + { + return Curses.idlok (Handle, bf); + } + + public void idcok (bool bf) + { + Curses.idcok (Handle, bf); + } + + public void immedok (bool bf) + { + Curses.immedok (Handle, bf); + } + + public int leaveok (bool bf) + { + return Curses.leaveok (Handle, bf); + } + + public int setscrreg (int top, int bot) + { + return Curses.wsetscrreg (Handle, top, bot); + } + + public int scrollok (bool bf) + { + return Curses.scrollok (Handle, bf); + } + + public int wrefresh () + { + return Curses.wrefresh (Handle); + } + + public int redrawwin () + { + return Curses.redrawwin (Handle); + } + +#if false + public int wredrawwin (int beg_line, int num_lines) + { + return Curses.wredrawwin (Handle, beg_line, num_lines); + } +#endif + public int wnoutrefresh () + { + return Curses.wnoutrefresh (Handle); + } + + public int move (int line, int col) + { + return Curses.wmove (Handle, line, col); + } + + public int addch (char ch) + { + return Curses.waddch (Handle, ch); + } + + public int refresh () + { + return Curses.wrefresh (Handle); + } + } + +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member + + +} diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/binding.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/binding.cs index 8a0ed3da78..6d84f62701 100644 --- a/Terminal.Gui/ConsoleDrivers/CursesDriver/binding.cs +++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/binding.cs @@ -64,7 +64,7 @@ public struct MouseEvent { } static int lines, cols; - static Window main_window; + static CursesWindow main_window; static IntPtr curses_handle, curscr_ptr, lines_ptr, cols_ptr; // If true, uses the DllImport into "ncurses", otherwise "libncursesw.so.5" @@ -97,7 +97,7 @@ static void FindNCurses () cols_ptr = get_ptr ("COLS"); } - static public Window initscr () + static public CursesWindow initscr () { setlocale (LC_ALL, ""); FindNCurses (); @@ -105,7 +105,7 @@ static public Window initscr () // Prevents the terminal from being locked after exiting. reset_shell_mode (); - main_window = new Window (methods.initscr ()); + main_window = new CursesWindow (methods.initscr ()); try { console_sharp_get_dims (out lines, out cols); } catch (DllNotFoundException) { diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/handles.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/handles.cs index 8a46149d50..ad3510aece 100644 --- a/Terminal.Gui/ConsoleDrivers/CursesDriver/handles.cs +++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/handles.cs @@ -30,131 +30,6 @@ namespace Unix.Terminal { #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member public partial class Curses { - public class Window { - public readonly IntPtr Handle; - static Window curscr; - static Window stdscr; - - static Window () - { - Curses.initscr (); - stdscr = new Window (Curses.console_sharp_get_stdscr ()); - curscr = new Window (Curses.console_sharp_get_curscr ()); - } - - internal Window (IntPtr handle) - { - Handle = handle; - } - - static public Window Standard { - get { - return stdscr; - } - } - - static public Window Current { - get { - return curscr; - } - } - - public int wtimeout (int delay) - { - return Curses.wtimeout (Handle, delay); - } - - public int notimeout (bool bf) - { - return Curses.notimeout (Handle, bf); - } - - public int keypad (bool bf) - { - return Curses.keypad (Handle, bf); - } - - public int meta (bool bf) - { - return Curses.meta (Handle, bf); - } - - public int intrflush (bool bf) - { - return Curses.intrflush (Handle, bf); - } - - public int clearok (bool bf) - { - return Curses.clearok (Handle, bf); - } - - public int idlok (bool bf) - { - return Curses.idlok (Handle, bf); - } - - public void idcok (bool bf) - { - Curses.idcok (Handle, bf); - } - - public void immedok (bool bf) - { - Curses.immedok (Handle, bf); - } - - public int leaveok (bool bf) - { - return Curses.leaveok (Handle, bf); - } - - public int setscrreg (int top, int bot) - { - return Curses.wsetscrreg (Handle, top, bot); - } - - public int scrollok (bool bf) - { - return Curses.scrollok (Handle, bf); - } - - public int wrefresh () - { - return Curses.wrefresh (Handle); - } - - public int redrawwin () - { - return Curses.redrawwin (Handle); - } - -#if false - public int wredrawwin (int beg_line, int num_lines) - { - return Curses.wredrawwin (Handle, beg_line, num_lines); - } -#endif - public int wnoutrefresh () - { - return Curses.wnoutrefresh (Handle); - } - - public int move (int line, int col) - { - return Curses.wmove (Handle, line, col); - } - - public int addch (char ch) - { - return Curses.waddch (Handle, ch); - } - - public int refresh () - { - return Curses.wrefresh (Handle); - } - } // Currently unused, to do later internal class Screen { diff --git a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeConsole.cs b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeConsole.cs index 75a58f9c32..852130f6cf 100644 --- a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeConsole.cs +++ b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeConsole.cs @@ -6,6 +6,9 @@ using System.IO; using System.Text; +// Alias Console to MockConsole so we don't accidentally use Console +using Console = Terminal.Gui.FakeConsole; + namespace Terminal.Gui { #pragma warning disable RCS1138 // Add summary to documentation comment. diff --git a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs index 2f7df9534d..509cefe874 100644 --- a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs @@ -3,7 +3,6 @@ // using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; using System.Threading; @@ -13,31 +12,16 @@ using Console = Terminal.Gui.FakeConsole; namespace Terminal.Gui { + /// /// Implements a mock ConsoleDriver for unit testing /// public class FakeDriver : ConsoleDriver { #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member - public class Behaviors { - - public bool UseFakeClipboard { get; internal set; } - public bool FakeClipboardAlwaysThrowsNotSupportedException { get; internal set; } - public bool FakeClipboardIsSupportedAlwaysFalse { get; internal set; } - - public Behaviors (bool useFakeClipboard = false, bool fakeClipboardAlwaysThrowsNotSupportedException = false, bool fakeClipboardIsSupportedAlwaysTrue = false) - { - UseFakeClipboard = useFakeClipboard; - FakeClipboardAlwaysThrowsNotSupportedException = fakeClipboardAlwaysThrowsNotSupportedException; - FakeClipboardIsSupportedAlwaysFalse = fakeClipboardIsSupportedAlwaysTrue; - - // double check usage is correct - Debug.Assert (useFakeClipboard == false && fakeClipboardAlwaysThrowsNotSupportedException == false); - Debug.Assert (useFakeClipboard == false && fakeClipboardIsSupportedAlwaysTrue == false); - } - } + - public static FakeDriver.Behaviors FakeBehaviors = new Behaviors (); + public static FakeDriverBehaviors FakeBehaviors = new FakeDriverBehaviors (); int cols, rows, left, top; public override int Cols => cols; diff --git a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriverBehaviors.cs b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriverBehaviors.cs new file mode 100644 index 0000000000..1ba2aa8cbc --- /dev/null +++ b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriverBehaviors.cs @@ -0,0 +1,26 @@ +// +// FakeDriver.cs: A fake ConsoleDriver for unit tests. +// +using System.Diagnostics; + +// Alias Console to MockConsole so we don't accidentally use Console + +namespace Terminal.Gui { + public class FakeDriverBehaviors { + + public bool UseFakeClipboard { get; internal set; } + public bool FakeClipboardAlwaysThrowsNotSupportedException { get; internal set; } + public bool FakeClipboardIsSupportedAlwaysFalse { get; internal set; } + + public FakeDriverBehaviors (bool useFakeClipboard = false, bool fakeClipboardAlwaysThrowsNotSupportedException = false, bool fakeClipboardIsSupportedAlwaysTrue = false) + { + UseFakeClipboard = useFakeClipboard; + FakeClipboardAlwaysThrowsNotSupportedException = fakeClipboardAlwaysThrowsNotSupportedException; + FakeClipboardIsSupportedAlwaysFalse = fakeClipboardIsSupportedAlwaysTrue; + + // double check usage is correct + Debug.Assert (useFakeClipboard == false && fakeClipboardAlwaysThrowsNotSupportedException == false); + Debug.Assert (useFakeClipboard == false && fakeClipboardIsSupportedAlwaysTrue == false); + } + } +} \ No newline at end of file diff --git a/Terminal.Gui/GlobalSuppressions.cs b/Terminal.Gui/GlobalSuppressions.cs new file mode 100644 index 0000000000..116da79d39 --- /dev/null +++ b/Terminal.Gui/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage ("Design", "CA1034:Nested types should not be visible", Justification = "", Scope = "type", Target = "~T:Terminal.Gui.SpinnerStyle.Custom")] diff --git a/Terminal.Gui/MainLoop.cs b/Terminal.Gui/MainLoop.cs index 777b70e9b8..58775c5c16 100644 --- a/Terminal.Gui/MainLoop.cs +++ b/Terminal.Gui/MainLoop.cs @@ -45,20 +45,7 @@ public interface IMainLoopDriver { /// Monitoring of file descriptors is only available on Unix, there /// does not seem to be a way of supporting this on Windows. /// - public class MainLoop { - /// - /// Provides data for timers running manipulation. - /// - public sealed class Timeout { - /// - /// Time to wait before invoke the callback. - /// - public TimeSpan Span; - /// - /// The function that will be invoked. - /// - public Func Callback; - } + public partial class MainLoop { internal SortedList timeouts = new SortedList (); object _timeoutsLockToken = new object (); diff --git a/Terminal.Gui/Timeout.cs b/Terminal.Gui/Timeout.cs new file mode 100644 index 0000000000..643aa3ba99 --- /dev/null +++ b/Terminal.Gui/Timeout.cs @@ -0,0 +1,24 @@ +// +// MainLoop.cs: IMainLoopDriver and MainLoop for Terminal.Gui +// +// Authors: +// Miguel de Icaza (miguel@gnome.org) +// +using System; + +namespace Terminal.Gui { + + /// + /// Provides data for timers running manipulation. + /// + public sealed class Timeout { + /// + /// Time to wait before invoke the callback. + /// + public TimeSpan Span; + /// + /// The function that will be invoked. + /// + public Func Callback; + } +} diff --git a/Terminal.Gui/Views/FileDialog.cs b/Terminal.Gui/Views/FileDialog.cs index 1e4d02e87e..67169af476 100644 --- a/Terminal.Gui/Views/FileDialog.cs +++ b/Terminal.Gui/Views/FileDialog.cs @@ -1147,7 +1147,7 @@ private void WriteStateToTableView () this.tableView.Update (); } - private ColorScheme ColorGetter (TableView.CellColorGetterArgs args) + private ColorScheme ColorGetter (CellColorGetterArgs args) { var stats = this.RowToStats (args.RowIndex); diff --git a/Terminal.Gui/Views/GraphView/Annotations.cs b/Terminal.Gui/Views/GraphView/Annotations.cs index 643b5acc6e..a1857210e2 100644 --- a/Terminal.Gui/Views/GraphView/Annotations.cs +++ b/Terminal.Gui/Views/GraphView/Annotations.cs @@ -213,7 +213,7 @@ public void AddEntry (GraphCellToRender graphCellToRender, string text) /// /// Sequence of lines to connect points e.g. of a /// - public class PathAnnotation : IAnnotation { + public partial class PathAnnotation : IAnnotation { /// /// Points that should be connected. Lines will be drawn between points in the order @@ -262,29 +262,5 @@ private IEnumerable PointsToLines () yield return new LineF (Points [i], Points [i + 1]); } } - - /// - /// Describes two points in graph space and a line between them - /// - public class LineF { - /// - /// The start of the line - /// - public PointF Start { get; } - - /// - /// The end point of the line - /// - public PointF End { get; } - - /// - /// Creates a new line between the points - /// - public LineF (PointF start, PointF end) - { - this.Start = start; - this.End = end; - } - } } } \ No newline at end of file diff --git a/Terminal.Gui/Views/GraphView/Bar.cs b/Terminal.Gui/Views/GraphView/Bar.cs new file mode 100644 index 0000000000..d1b40d3279 --- /dev/null +++ b/Terminal.Gui/Views/GraphView/Bar.cs @@ -0,0 +1,40 @@ +namespace Terminal.Gui { + + /// + /// A single bar in a + /// + public class Bar { + + /// + /// Optional text that describes the bar. This will be rendered on the corresponding + /// unless is false + /// + public string Text { get; set; } + + /// + /// The color and character that will be rendered in the console + /// when the bar extends over it + /// + public GraphCellToRender Fill { get; set; } + + /// + /// The value in graph space X/Y (depending on ) to which the bar extends. + /// + public float Value { get; } + + /// + /// Creates a new instance of a single bar rendered in the given that extends + /// out graph space units in the default + /// + /// + /// + /// + public Bar (string text, GraphCellToRender fill, float value) + { + Text = text; + Fill = fill; + Value = value; + } + } + +} \ No newline at end of file diff --git a/Terminal.Gui/Views/GraphView/LineF.cs b/Terminal.Gui/Views/GraphView/LineF.cs new file mode 100644 index 0000000000..623c6dbbc7 --- /dev/null +++ b/Terminal.Gui/Views/GraphView/LineF.cs @@ -0,0 +1,27 @@ +namespace Terminal.Gui { + + /// + /// Describes two points in graph space and a line between them + /// + public class LineF { + /// + /// The start of the line + /// + public PointF Start { get; } + + /// + /// The end point of the line + /// + public PointF End { get; } + + /// + /// Creates a new line between the points + /// + public LineF (PointF start, PointF end) + { + this.Start = start; + this.End = end; + } + } + +} \ No newline at end of file diff --git a/Terminal.Gui/Views/GraphView/Series.cs b/Terminal.Gui/Views/GraphView/Series.cs index c6618cc4f4..a5d50a8da5 100644 --- a/Terminal.Gui/Views/GraphView/Series.cs +++ b/Terminal.Gui/Views/GraphView/Series.cs @@ -72,7 +72,7 @@ public class MultiBarSeries : ISeries { /// /// The number of units of graph space between bars. Should be - /// less than + /// less than /// public float Spacing { get; } @@ -119,7 +119,7 @@ public void AddBars (string label, Rune fill, params float [] values) } for (int i = 0; i < values.Length; i++) { - subSeries [i].Bars.Add (new BarSeries.Bar (label, + subSeries [i].Bars.Add (new Bar (label, new GraphCellToRender (fill), values [i])); } } @@ -142,7 +142,7 @@ public void DrawSeries (GraphView graph, Rect drawBounds, RectangleF graphBounds /// /// Series of bars positioned at regular intervals /// - public class BarSeries : ISeries { + public partial class BarSeries : ISeries { /// /// Ordered collection of graph bars to position along axis @@ -280,42 +280,5 @@ protected virtual void DrawBarLine (GraphView graph, Point start, Point end, Bar graph.SetDriverColorToGraphColor (); } - - /// - /// A single bar in a - /// - public class Bar { - - /// - /// Optional text that describes the bar. This will be rendered on the corresponding - /// unless is false - /// - public string Text { get; set; } - - /// - /// The color and character that will be rendered in the console - /// when the bar extends over it - /// - public GraphCellToRender Fill { get; set; } - - /// - /// The value in graph space X/Y (depending on ) to which the bar extends. - /// - public float Value { get; } - - /// - /// Creates a new instance of a single bar rendered in the given that extends - /// out graph space units in the default - /// - /// - /// - /// - public Bar (string text, GraphCellToRender fill, float value) - { - Text = text; - Fill = fill; - Value = value; - } - } } } \ No newline at end of file diff --git a/Terminal.Gui/Views/TableView/CellColorGetterArgs.cs b/Terminal.Gui/Views/TableView/CellColorGetterArgs.cs new file mode 100644 index 0000000000..50d97716a8 --- /dev/null +++ b/Terminal.Gui/Views/TableView/CellColorGetterArgs.cs @@ -0,0 +1,50 @@ +namespace Terminal.Gui { + + /// + /// Arguments for a . Describes a cell for which a rendering + /// is being sought + /// + public class CellColorGetterArgs { + + /// + /// The data table hosted by the control. + /// + public ITableSource Table { get; } + + /// + /// The index of the row in for which color is needed + /// + public int RowIndex { get; } + + /// + /// The index of column in for which color is needed + /// + public int ColIdex { get; } + + /// + /// The hard typed value being rendered in the cell for which color is needed + /// + public object CellValue { get; } + + /// + /// The textual representation of (what will actually be drawn to the screen) + /// + public string Representation { get; } + + /// + /// the color scheme that is going to be used to render the cell if no cell specific color scheme is returned + /// + public ColorScheme RowScheme { get; } + + internal CellColorGetterArgs (ITableSource table, int rowIdx, int colIdx, object cellValue, string representation, ColorScheme rowScheme) + { + Table = table; + RowIndex = rowIdx; + ColIdex = colIdx; + CellValue = cellValue; + Representation = representation; + RowScheme = rowScheme; + } + + } +} \ No newline at end of file diff --git a/Terminal.Gui/Views/TableView/ListColumnStyle.cs b/Terminal.Gui/Views/TableView/ListColumnStyle.cs new file mode 100644 index 0000000000..76421ccac5 --- /dev/null +++ b/Terminal.Gui/Views/TableView/ListColumnStyle.cs @@ -0,0 +1,19 @@ +namespace Terminal.Gui { + /// + /// Defines rendering options that affect how the view is displayed. + /// + public class ListColumnStyle { + + /// + /// Gets or sets an Orientation enum indicating whether to populate data down each column + /// rather than across each row. Defaults to . + /// + public Orientation Orientation { get; set; } = Orientation.Horizontal; + + /// + /// Gets or sets a flag indicating whether to scroll in the same direction as . + /// Defaults to . + /// + public bool ScrollParallel { get; set; } = false; + } +} diff --git a/Terminal.Gui/Views/TableView/ListTableSource.cs b/Terminal.Gui/Views/TableView/ListTableSource.cs index 81dc22ba4a..ef75bd25fd 100644 --- a/Terminal.Gui/Views/TableView/ListTableSource.cs +++ b/Terminal.Gui/Views/TableView/ListTableSource.cs @@ -9,7 +9,7 @@ namespace Terminal.Gui { /// a . This class is /// mutable: changes are permitted to the wrapped . /// - public class ListTableSource : ITableSource { + public partial class ListTableSource : ITableSource { /// /// The list this source wraps. /// @@ -174,23 +174,5 @@ private int CalculateColumns () return (cols > 1) ? cols : 1; } - - /// - /// Defines rendering options that affect how the view is displayed. - /// - public class ListColumnStyle { - - /// - /// Gets or sets an Orientation enum indicating whether to populate data down each column - /// rather than across each row. Defaults to . - /// - public Orientation Orientation { get; set; } = Orientation.Horizontal; - - /// - /// Gets or sets a flag indicating whether to scroll in the same direction as . - /// Defaults to . - /// - public bool ScrollParallel { get; set; } = false; - } } } diff --git a/Terminal.Gui/Views/TableView/RowColorGetterArgs.cs b/Terminal.Gui/Views/TableView/RowColorGetterArgs.cs new file mode 100644 index 0000000000..220d8fdeb2 --- /dev/null +++ b/Terminal.Gui/Views/TableView/RowColorGetterArgs.cs @@ -0,0 +1,25 @@ +namespace Terminal.Gui { + + /// + /// Arguments for . Describes a row of data in a + /// for which is sought. + /// + public class RowColorGetterArgs { + + /// + /// The data table hosted by the control. + /// + public ITableSource Table { get; } + + /// + /// The index of the row in for which color is needed + /// + public int RowIndex { get; } + + internal RowColorGetterArgs (ITableSource table, int rowIdx) + { + Table = table; + RowIndex = rowIdx; + } + } +} \ No newline at end of file diff --git a/Terminal.Gui/Views/TableView/TableView.cs b/Terminal.Gui/Views/TableView/TableView.cs index 6363d33ef5..c9d9dcee5f 100644 --- a/Terminal.Gui/Views/TableView/TableView.cs +++ b/Terminal.Gui/Views/TableView/TableView.cs @@ -13,7 +13,7 @@ namespace Terminal.Gui { /// /// See TableView Deep Dive for more information. /// - public class TableView : View { + public partial class TableView : View { private int columnOffset; private int rowOffset; @@ -2046,77 +2046,6 @@ public ColumnToRender (int col, int x, int width, bool isVeryLast) } - /// - /// Arguments for a . Describes a cell for which a rendering - /// is being sought - /// - public class CellColorGetterArgs { - - /// - /// The data table hosted by the control. - /// - public ITableSource Table { get; } - - /// - /// The index of the row in for which color is needed - /// - public int RowIndex { get; } - - /// - /// The index of column in for which color is needed - /// - public int ColIdex { get; } - - /// - /// The hard typed value being rendered in the cell for which color is needed - /// - public object CellValue { get; } - - /// - /// The textual representation of (what will actually be drawn to the screen) - /// - public string Representation { get; } - - /// - /// the color scheme that is going to be used to render the cell if no cell specific color scheme is returned - /// - public ColorScheme RowScheme { get; } - - internal CellColorGetterArgs (ITableSource table, int rowIdx, int colIdx, object cellValue, string representation, ColorScheme rowScheme) - { - Table = table; - RowIndex = rowIdx; - ColIdex = colIdx; - CellValue = cellValue; - Representation = representation; - RowScheme = rowScheme; - } - - } - - /// - /// Arguments for . Describes a row of data in a - /// for which is sought. - /// - public class RowColorGetterArgs { - - /// - /// The data table hosted by the control. - /// - public ITableSource Table { get; } - - /// - /// The index of the row in for which color is needed - /// - public int RowIndex { get; } - - internal RowColorGetterArgs (ITableSource table, int rowIdx) - { - Table = table; - RowIndex = rowIdx; - } - } - /// /// Describes a selected region of the table /// diff --git a/Terminal.Gui/Views/Tile.cs b/Terminal.Gui/Views/Tile.cs new file mode 100644 index 0000000000..34a8caf01f --- /dev/null +++ b/Terminal.Gui/Views/Tile.cs @@ -0,0 +1,95 @@ +using System; + +namespace Terminal.Gui { + + /// + /// A single presented in a . To create + /// new instances use + /// or . + /// + public class Tile { + /// + /// The that is contained in this . + /// Add new child views to this member for multiple + /// s within the . + /// + public View ContentView { get; internal set; } + + /// + /// Gets or Sets the minimum size you to allow when splitter resizing along + /// parent direction. + /// + public int MinSize { get; set; } + + /// + /// The text that should be displayed above the . This + /// will appear over the splitter line or border (above the view client area). + /// + /// + /// Title are not rendered for root level tiles + /// is . + /// + public string Title { + get => _title; + set { + if (!OnTitleChanging (_title, value)) { + var old = _title; + _title = value; + OnTitleChanged (old, _title); + return; + } + _title = value; + } + } + + private string _title = string.Empty; + + /// + /// 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 cancelled the Title change. + public virtual bool OnTitleChanging (string oldTitle, string newTitle) + { + var args = new TitleEventArgs (oldTitle, newTitle); + TitleChanging?.Invoke (this, args); + return args.Cancel; + } + + /// + /// Event fired when the is changing. Set to + /// true to cancel the Title change. + /// + public event EventHandler 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 (string oldTitle, string newTitle) + { + var args = new TitleEventArgs (oldTitle, newTitle); + TitleChanged?.Invoke (this, args); + } + + /// + /// Event fired after the has been changed. + /// + public event EventHandler TitleChanged; + + /// + /// Creates a new instance of the class. + /// + public Tile () + { + ContentView = new View () { Width = Dim.Fill (), Height = Dim.Fill () }; +#if DEBUG_IDISPOSABLE + ContentView.Data = "Tile.ContentView"; +#endif + Title = string.Empty; + MinSize = 0; + } + } +} diff --git a/Terminal.Gui/Views/TileView.cs b/Terminal.Gui/Views/TileView.cs index 117891cdac..7a04cd2f91 100644 --- a/Terminal.Gui/Views/TileView.cs +++ b/Terminal.Gui/Views/TileView.cs @@ -9,7 +9,7 @@ namespace Terminal.Gui { /// A consisting of a moveable bar that divides /// the display area into resizeable . /// - public class TileView : View { + public partial class TileView : View { TileView parentTileView; /// @@ -18,97 +18,6 @@ public class TileView : View { /// public Key ToggleResizable { get; set; } = Key.CtrlMask | Key.F10; - /// - /// A single presented in a . To create - /// new instances use - /// or . - /// - public class Tile { - /// - /// The that is contained in this . - /// Add new child views to this member for multiple - /// s within the . - /// - public View ContentView { get; internal set; } - - /// - /// Gets or Sets the minimum size you to allow when splitter resizing along - /// parent direction. - /// - public int MinSize { get; set; } - - /// - /// The text that should be displayed above the . This - /// will appear over the splitter line or border (above the view client area). - /// - /// - /// Title are not rendered for root level tiles - /// is . - /// - public string Title { - get => _title; - set { - if (!OnTitleChanging (_title, value)) { - var old = _title; - _title = value; - OnTitleChanged (old, _title); - return; - } - _title = value; - } - } - - private string _title = string.Empty; - - /// - /// 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 cancelled the Title change. - public virtual bool OnTitleChanging (string oldTitle, string newTitle) - { - var args = new TitleEventArgs (oldTitle, newTitle); - TitleChanging?.Invoke (this, args); - return args.Cancel; - } - - /// - /// Event fired when the is changing. Set to - /// true to cancel the Title change. - /// - public event EventHandler 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 (string oldTitle, string newTitle) - { - var args = new TitleEventArgs (oldTitle, newTitle); - TitleChanged?.Invoke (this, args); - } - - /// - /// Event fired after the has been changed. - /// - public event EventHandler TitleChanged; - - /// - /// Creates a new instance of the class. - /// - public Tile () - { - ContentView = new View () { Width = Dim.Fill (), Height = Dim.Fill () }; -#if DEBUG_IDISPOSABLE - ContentView.Data = "Tile.ContentView"; -#endif - Title = string.Empty; - MinSize = 0; - } - } - List tiles; private List splitterDistances; private List splitterLines; diff --git a/Terminal.Gui/Views/Wizard/Wizard.cs b/Terminal.Gui/Views/Wizard/Wizard.cs index 2acd040af5..138a404c72 100644 --- a/Terminal.Gui/Views/Wizard/Wizard.cs +++ b/Terminal.Gui/Views/Wizard/Wizard.cs @@ -28,13 +28,13 @@ namespace Terminal.Gui { /// var wizard = new Wizard ($"Setup Wizard"); /// /// // Add 1st step - /// var firstStep = new Wizard.WizardStep ("End User License Agreement"); + /// var firstStep = new WizardStep ("End User License Agreement"); /// wizard.AddStep(firstStep); /// firstStep.NextButtonText = "Accept!"; /// firstStep.HelpText = "This is the End User License Agreement."; /// /// // Add 2nd step - /// var secondStep = new Wizard.WizardStep ("Second Step"); + /// var secondStep = new WizardStep ("Second Step"); /// wizard.AddStep(secondStep); /// secondStep.HelpText = "This is the help text for the Second Step."; /// var lbl = new Label ("Name:") { AutoSize = true }; @@ -54,213 +54,7 @@ namespace Terminal.Gui { /// Application.Shutdown (); /// /// - public class Wizard : Dialog { - /// - /// Represents a basic step that is displayed in a . The view is divided horizontally in two. On the left is the - /// content view where s can be added, On the right is the help for the step. - /// Set to set the help text. If the help text is empty the help pane will not - /// be shown. - /// - /// If there are no Views added to the WizardStep the (if not empty) will fill the wizard step. - /// - /// - /// If s are added, do not set to true as this will conflict - /// with the Next button of the Wizard. - /// - /// Subscribe to the event to be notified when the step is active; see also: . - /// - /// To enable or disable a step from being shown to the user, set . - /// - /// - public class WizardStep : FrameView { - ///// - ///// The title of the . - ///// - ///// The Title is only displayed when the is used as a modal pop-up (see . - //public new string Title { - // // BUGBUG: v2 - No need for this as View now has Title w/ notifications. - // get => title; - // set { - // if (!OnTitleChanging (title, value)) { - // var old = title; - // title = value; - // OnTitleChanged (old, title); - // } - // base.Title = value; - // SetNeedsDisplay (); - // } - //} - - //private string title = string.Empty; - - // The contentView works like the ContentView in FrameView. - private View contentView = new View () { Data = "WizardContentView" }; - - /// - /// Sets or gets help text for the .If is empty - /// the help pane will not be visible and the content will fill the entire WizardStep. - /// - /// The help text is displayed using a read-only . - public string HelpText { - get => helpTextView.Text; - set { - helpTextView.Text = value; - ShowHide (); - SetNeedsDisplay (); - } - } - private TextView helpTextView = new TextView (); - - /// - /// Sets or gets the text for the back button. The back button will only be visible on - /// steps after the first step. - /// - /// The default text is "Back" - public string BackButtonText { get; set; } = string.Empty; - - /// - /// Sets or gets the text for the next/finish button. - /// - /// The default text is "Next..." if the Pane is not the last pane. Otherwise it is "Finish" - public string NextButtonText { get; set; } = string.Empty; - - /// - /// Initializes a new instance of the class using positioning. - /// - public WizardStep () - { - BorderStyle = LineStyle.None; - base.Add (contentView); - - helpTextView.ReadOnly = true; - helpTextView.WordWrap = true; - base.Add (helpTextView); - - // BUGBUG: v2 - Disabling scrolling for now - //var scrollBar = new ScrollBarView (helpTextView, true); - - //scrollBar.ChangedPosition += (s,e) => { - // helpTextView.TopRow = scrollBar.Position; - // if (helpTextView.TopRow != scrollBar.Position) { - // scrollBar.Position = helpTextView.TopRow; - // } - // helpTextView.SetNeedsDisplay (); - //}; - - //scrollBar.OtherScrollBarView.ChangedPosition += (s,e) => { - // helpTextView.LeftColumn = scrollBar.OtherScrollBarView.Position; - // if (helpTextView.LeftColumn != scrollBar.OtherScrollBarView.Position) { - // scrollBar.OtherScrollBarView.Position = helpTextView.LeftColumn; - // } - // helpTextView.SetNeedsDisplay (); - //}; - - //scrollBar.VisibleChanged += (s,e) => { - // if (scrollBar.Visible && helpTextView.RightOffset == 0) { - // helpTextView.RightOffset = 1; - // } else if (!scrollBar.Visible && helpTextView.RightOffset == 1) { - // helpTextView.RightOffset = 0; - // } - //}; - - //scrollBar.OtherScrollBarView.VisibleChanged += (s,e) => { - // if (scrollBar.OtherScrollBarView.Visible && helpTextView.BottomOffset == 0) { - // helpTextView.BottomOffset = 1; - // } else if (!scrollBar.OtherScrollBarView.Visible && helpTextView.BottomOffset == 1) { - // helpTextView.BottomOffset = 0; - // } - //}; - - //helpTextView.DrawContent += (s,e) => { - // scrollBar.Size = helpTextView.Lines; - // scrollBar.Position = helpTextView.TopRow; - // if (scrollBar.OtherScrollBarView != null) { - // scrollBar.OtherScrollBarView.Size = helpTextView.Maxlength; - // scrollBar.OtherScrollBarView.Position = helpTextView.LeftColumn; - // } - // scrollBar.LayoutSubviews (); - // scrollBar.Refresh (); - //}; - //base.Add (scrollBar); - ShowHide (); - } - - /// - /// Does the work to show and hide the contentView and helpView as appropriate - /// - internal void ShowHide () - { - contentView.Height = Dim.Fill (); - helpTextView.Height = Dim.Fill (); - helpTextView.Width = Dim.Fill (); - - if (contentView.InternalSubviews?.Count > 0) { - if (helpTextView.Text.Length > 0) { - contentView.Width = Dim.Percent (70); - helpTextView.X = Pos.Right (contentView); - helpTextView.Width = Dim.Fill (); - - } else { - contentView.Width = Dim.Fill (); - } - } else { - if (helpTextView.Text.Length > 0) { - helpTextView.X = 0; - } else { - // Error - no pane shown - } - - } - contentView.Visible = contentView.InternalSubviews?.Count > 0; - helpTextView.Visible = helpTextView.Text.Length > 0; - } - - /// - /// Add the specified to the . - /// - /// to add to this container - public override void Add (View view) - { - contentView.Add (view); - if (view.CanFocus) { - CanFocus = true; - } - ShowHide (); - } - - /// - /// Removes a from . - /// - /// - /// - public override void Remove (View view) - { - if (view == null) { - return; - } - - SetNeedsDisplay (); - var touched = view.Frame; - contentView.Remove (view); - - if (contentView.InternalSubviews.Count < 1) { - this.CanFocus = false; - } - ShowHide (); - } - - /// - /// Removes all s from the . - /// - /// - /// - public override void RemoveAll () - { - contentView.RemoveAll (); - ShowHide (); - } - - } // end of WizardStep class + public partial class Wizard : Dialog { /// /// Initializes a new instance of the class using positioning. diff --git a/Terminal.Gui/Views/Wizard/WizardStep.cs b/Terminal.Gui/Views/Wizard/WizardStep.cs new file mode 100644 index 0000000000..bc72c0c723 --- /dev/null +++ b/Terminal.Gui/Views/Wizard/WizardStep.cs @@ -0,0 +1,209 @@ +namespace Terminal.Gui { + + /// + /// Represents a basic step that is displayed in a . The view is divided horizontally in two. On the left is the + /// content view where s can be added, On the right is the help for the step. + /// Set to set the help text. If the help text is empty the help pane will not + /// be shown. + /// + /// If there are no Views added to the WizardStep the (if not empty) will fill the wizard step. + /// + /// + /// If s are added, do not set to true as this will conflict + /// with the Next button of the Wizard. + /// + /// Subscribe to the event to be notified when the step is active; see also: . + /// + /// To enable or disable a step from being shown to the user, set . + /// + /// + public class WizardStep : FrameView { + ///// + ///// The title of the . + ///// + ///// The Title is only displayed when the is used as a modal pop-up (see . + //public new string Title { + // // BUGBUG: v2 - No need for this as View now has Title w/ notifications. + // get => title; + // set { + // if (!OnTitleChanging (title, value)) { + // var old = title; + // title = value; + // OnTitleChanged (old, title); + // } + // base.Title = value; + // SetNeedsDisplay (); + // } + //} + + //private string title = string.Empty; + + // The contentView works like the ContentView in FrameView. + private View contentView = new View () { Data = "WizardContentView" }; + + /// + /// Sets or gets help text for the .If is empty + /// the help pane will not be visible and the content will fill the entire WizardStep. + /// + /// The help text is displayed using a read-only . + public string HelpText { + get => helpTextView.Text; + set { + helpTextView.Text = value; + ShowHide (); + SetNeedsDisplay (); + } + } + private TextView helpTextView = new TextView (); + + /// + /// Sets or gets the text for the back button. The back button will only be visible on + /// steps after the first step. + /// + /// The default text is "Back" + public string BackButtonText { get; set; } = string.Empty; + + /// + /// Sets or gets the text for the next/finish button. + /// + /// The default text is "Next..." if the Pane is not the last pane. Otherwise it is "Finish" + public string NextButtonText { get; set; } = string.Empty; + + /// + /// Initializes a new instance of the class using positioning. + /// + public WizardStep () + { + BorderStyle = LineStyle.None; + base.Add (contentView); + + helpTextView.ReadOnly = true; + helpTextView.WordWrap = true; + base.Add (helpTextView); + + // BUGBUG: v2 - Disabling scrolling for now + //var scrollBar = new ScrollBarView (helpTextView, true); + + //scrollBar.ChangedPosition += (s,e) => { + // helpTextView.TopRow = scrollBar.Position; + // if (helpTextView.TopRow != scrollBar.Position) { + // scrollBar.Position = helpTextView.TopRow; + // } + // helpTextView.SetNeedsDisplay (); + //}; + + //scrollBar.OtherScrollBarView.ChangedPosition += (s,e) => { + // helpTextView.LeftColumn = scrollBar.OtherScrollBarView.Position; + // if (helpTextView.LeftColumn != scrollBar.OtherScrollBarView.Position) { + // scrollBar.OtherScrollBarView.Position = helpTextView.LeftColumn; + // } + // helpTextView.SetNeedsDisplay (); + //}; + + //scrollBar.VisibleChanged += (s,e) => { + // if (scrollBar.Visible && helpTextView.RightOffset == 0) { + // helpTextView.RightOffset = 1; + // } else if (!scrollBar.Visible && helpTextView.RightOffset == 1) { + // helpTextView.RightOffset = 0; + // } + //}; + + //scrollBar.OtherScrollBarView.VisibleChanged += (s,e) => { + // if (scrollBar.OtherScrollBarView.Visible && helpTextView.BottomOffset == 0) { + // helpTextView.BottomOffset = 1; + // } else if (!scrollBar.OtherScrollBarView.Visible && helpTextView.BottomOffset == 1) { + // helpTextView.BottomOffset = 0; + // } + //}; + + //helpTextView.DrawContent += (s,e) => { + // scrollBar.Size = helpTextView.Lines; + // scrollBar.Position = helpTextView.TopRow; + // if (scrollBar.OtherScrollBarView != null) { + // scrollBar.OtherScrollBarView.Size = helpTextView.Maxlength; + // scrollBar.OtherScrollBarView.Position = helpTextView.LeftColumn; + // } + // scrollBar.LayoutSubviews (); + // scrollBar.Refresh (); + //}; + //base.Add (scrollBar); + ShowHide (); + } + + /// + /// Does the work to show and hide the contentView and helpView as appropriate + /// + internal void ShowHide () + { + contentView.Height = Dim.Fill (); + helpTextView.Height = Dim.Fill (); + helpTextView.Width = Dim.Fill (); + + if (contentView.InternalSubviews?.Count > 0) { + if (helpTextView.Text.Length > 0) { + contentView.Width = Dim.Percent (70); + helpTextView.X = Pos.Right (contentView); + helpTextView.Width = Dim.Fill (); + + } else { + contentView.Width = Dim.Fill (); + } + } else { + if (helpTextView.Text.Length > 0) { + helpTextView.X = 0; + } else { + // Error - no pane shown + } + + } + contentView.Visible = contentView.InternalSubviews?.Count > 0; + helpTextView.Visible = helpTextView.Text.Length > 0; + } + + /// + /// Add the specified to the . + /// + /// to add to this container + public override void Add (View view) + { + contentView.Add (view); + if (view.CanFocus) { + CanFocus = true; + } + ShowHide (); + } + + /// + /// Removes a from . + /// + /// + /// + public override void Remove (View view) + { + if (view == null) { + return; + } + + SetNeedsDisplay (); + var touched = view.Frame; + contentView.Remove (view); + + if (contentView.InternalSubviews.Count < 1) { + this.CanFocus = false; + } + ShowHide (); + } + + /// + /// Removes all s from the . + /// + /// + /// + public override void RemoveAll () + { + contentView.RemoveAll (); + ShowHide (); + } + + } // end of WizardStep class +} \ No newline at end of file diff --git a/UICatalog/Scenarios/ConfigurationEditor.cs b/UICatalog/Scenarios/ConfigurationEditor.cs index cd7e6f2c42..11c04e62c1 100644 --- a/UICatalog/Scenarios/ConfigurationEditor.cs +++ b/UICatalog/Scenarios/ConfigurationEditor.cs @@ -75,7 +75,7 @@ public override void Setup () } private class ConfigTextView : TextView { - internal TileView.Tile Tile { get; set; } + internal Tile Tile { get; set; } internal FileInfo FileInfo { get; set; } internal ConfigTextView () diff --git a/UICatalog/Scenarios/GraphViewExample.cs b/UICatalog/Scenarios/GraphViewExample.cs index ed5d6fb20b..703a94af23 100644 --- a/UICatalog/Scenarios/GraphViewExample.cs +++ b/UICatalog/Scenarios/GraphViewExample.cs @@ -302,24 +302,24 @@ private void SetupLifeExpectancyBarGraph (bool verticalBars) var mediumStiple = new GraphCellToRender ((Rune)'\u2592'); var barSeries = new BarSeries () { - Bars = new List () { - new BarSeries.Bar ("Switzerland", softStiple, 83.4f), - new BarSeries.Bar ("South Korea", !verticalBars?mediumStiple:softStiple, 83.3f), - new BarSeries.Bar ("Singapore", softStiple, 83.2f), - new BarSeries.Bar ("Spain", !verticalBars?mediumStiple:softStiple, 83.2f), - new BarSeries.Bar ("Cyprus", softStiple, 83.1f), - new BarSeries.Bar ("Australia", !verticalBars?mediumStiple:softStiple, 83), - new BarSeries.Bar ("Italy", softStiple, 83), - new BarSeries.Bar ("Norway", !verticalBars?mediumStiple:softStiple, 83), - new BarSeries.Bar ("Israel", softStiple, 82.6f), - new BarSeries.Bar ("France", !verticalBars?mediumStiple:softStiple, 82.5f), - new BarSeries.Bar ("Luxembourg", softStiple, 82.4f), - new BarSeries.Bar ("Sweden", !verticalBars?mediumStiple:softStiple, 82.4f), - new BarSeries.Bar ("Iceland", softStiple, 82.3f), - new BarSeries.Bar ("Canada", !verticalBars?mediumStiple:softStiple, 82.2f), - new BarSeries.Bar ("New Zealand", softStiple, 82), - new BarSeries.Bar ("Malta", !verticalBars?mediumStiple:softStiple, 81.9f), - new BarSeries.Bar ("Ireland", softStiple, 81.8f) + Bars = new List () { + new Bar ("Switzerland", softStiple, 83.4f), + new Bar ("South Korea", !verticalBars?mediumStiple:softStiple, 83.3f), + new Bar ("Singapore", softStiple, 83.2f), + new Bar ("Spain", !verticalBars?mediumStiple:softStiple, 83.2f), + new Bar ("Cyprus", softStiple, 83.1f), + new Bar ("Australia", !verticalBars?mediumStiple:softStiple, 83), + new Bar ("Italy", softStiple, 83), + new Bar ("Norway", !verticalBars?mediumStiple:softStiple, 83), + new Bar ("Israel", softStiple, 82.6f), + new Bar ("France", !verticalBars?mediumStiple:softStiple, 82.5f), + new Bar ("Luxembourg", softStiple, 82.4f), + new Bar ("Sweden", !verticalBars?mediumStiple:softStiple, 82.4f), + new Bar ("Iceland", softStiple, 82.3f), + new Bar ("Canada", !verticalBars?mediumStiple:softStiple, 82.2f), + new Bar ("New Zealand", softStiple, 82), + new Bar ("Malta", !verticalBars?mediumStiple:softStiple, 81.9f), + new Bar ("Ireland", softStiple, 81.8f) } }; @@ -436,29 +436,29 @@ private void SetupPopulationPyramid () // Males (negative to make the bars go left) var malesSeries = new BarSeries () { Orientation = Orientation.Horizontal, - Bars = new List () + Bars = new List () { - new BarSeries.Bar("0-4",stiple,-2009363), - new BarSeries.Bar("5-9",stiple,-2108550), - new BarSeries.Bar("10-14",stiple,-2022370), - new BarSeries.Bar("15-19",stiple,-1880611), - new BarSeries.Bar("20-24",stiple,-2072674), - new BarSeries.Bar("25-29",stiple,-2275138), - new BarSeries.Bar("30-34",stiple,-2361054), - new BarSeries.Bar("35-39",stiple,-2279836), - new BarSeries.Bar("40-44",stiple,-2148253), - new BarSeries.Bar("45-49",stiple,-2128343), - new BarSeries.Bar("50-54",stiple,-2281421), - new BarSeries.Bar("55-59",stiple,-2232388), - new BarSeries.Bar("60-64",stiple,-1919839), - new BarSeries.Bar("65-69",stiple,-1647391), - new BarSeries.Bar("70-74",stiple,-1624635), - new BarSeries.Bar("75-79",stiple,-1137438), - new BarSeries.Bar("80-84",stiple,-766956), - new BarSeries.Bar("85-89",stiple,-438663), - new BarSeries.Bar("90-94",stiple,-169952), - new BarSeries.Bar("95-99",stiple,-34524), - new BarSeries.Bar("100+",stiple,-3016) + new Bar("0-4",stiple,-2009363), + new Bar("5-9",stiple,-2108550), + new Bar("10-14",stiple,-2022370), + new Bar("15-19",stiple,-1880611), + new Bar("20-24",stiple,-2072674), + new Bar("25-29",stiple,-2275138), + new Bar("30-34",stiple,-2361054), + new Bar("35-39",stiple,-2279836), + new Bar("40-44",stiple,-2148253), + new Bar("45-49",stiple,-2128343), + new Bar("50-54",stiple,-2281421), + new Bar("55-59",stiple,-2232388), + new Bar("60-64",stiple,-1919839), + new Bar("65-69",stiple,-1647391), + new Bar("70-74",stiple,-1624635), + new Bar("75-79",stiple,-1137438), + new Bar("80-84",stiple,-766956), + new Bar("85-89",stiple,-438663), + new Bar("90-94",stiple,-169952), + new Bar("95-99",stiple,-34524), + new Bar("100+",stiple,-3016) } }; @@ -467,29 +467,29 @@ private void SetupPopulationPyramid () // Females var femalesSeries = new BarSeries () { Orientation = Orientation.Horizontal, - Bars = new List () + Bars = new List () { - new BarSeries.Bar("0-4",stiple,1915127), - new BarSeries.Bar("5-9",stiple,2011016), - new BarSeries.Bar("10-14",stiple,1933970), - new BarSeries.Bar("15-19",stiple,1805522), - new BarSeries.Bar("20-24",stiple,2001966), - new BarSeries.Bar("25-29",stiple,2208929), - new BarSeries.Bar("30-34",stiple,2345774), - new BarSeries.Bar("35-39",stiple,2308360), - new BarSeries.Bar("40-44",stiple,2159877), - new BarSeries.Bar("45-49",stiple,2167778), - new BarSeries.Bar("50-54",stiple,2353119), - new BarSeries.Bar("55-59",stiple,2306537), - new BarSeries.Bar("60-64",stiple,1985177), - new BarSeries.Bar("65-69",stiple,1734370), - new BarSeries.Bar("70-74",stiple,1763853), - new BarSeries.Bar("75-79",stiple,1304709), - new BarSeries.Bar("80-84",stiple,969611), - new BarSeries.Bar("85-89",stiple,638892), - new BarSeries.Bar("90-94",stiple,320625), - new BarSeries.Bar("95-99",stiple,95559), - new BarSeries.Bar("100+",stiple,12818) + new Bar("0-4",stiple,1915127), + new Bar("5-9",stiple,2011016), + new Bar("10-14",stiple,1933970), + new Bar("15-19",stiple,1805522), + new Bar("20-24",stiple,2001966), + new Bar("25-29",stiple,2208929), + new Bar("30-34",stiple,2345774), + new Bar("35-39",stiple,2308360), + new Bar("40-44",stiple,2159877), + new Bar("45-49",stiple,2167778), + new Bar("50-54",stiple,2353119), + new Bar("55-59",stiple,2306537), + new Bar("60-64",stiple,1985177), + new Bar("65-69",stiple,1734370), + new Bar("70-74",stiple,1763853), + new Bar("75-79",stiple,1304709), + new Bar("80-84",stiple,969611), + new Bar("85-89",stiple,638892), + new Bar("90-94",stiple,320625), + new Bar("95-99",stiple,95559), + new Bar("100+",stiple,12818) } }; @@ -564,7 +564,7 @@ private void SetupDisco () Random r = new Random (); var series = new DiscoBarSeries (); - var bars = new List (); + var bars = new List (); Func genSample = (l) => { @@ -572,7 +572,7 @@ private void SetupDisco () // generate an imaginary sample for (int i = 0; i < 31; i++) { bars.Add ( - new BarSeries.Bar (null, stiple, r.Next (0, 100)) { + new Bar (null, stiple, r.Next (0, 100)) { //ColorGetter = colorDelegate }); } diff --git a/UICatalog/Scenarios/ListColumns.cs b/UICatalog/Scenarios/ListColumns.cs index cf6b7bb62f..5980cea376 100644 --- a/UICatalog/Scenarios/ListColumns.cs +++ b/UICatalog/Scenarios/ListColumns.cs @@ -49,7 +49,7 @@ public override void Setup () ExpandLastColumn = false, } }; - var listColStyle = new ListTableSource.ListColumnStyle (); + var listColStyle = new ListColumnStyle (); var menu = new MenuBar (new MenuBarItem [] { new MenuBarItem ("_File", new MenuItem [] { diff --git a/UICatalog/Scenarios/WizardAsView.cs b/UICatalog/Scenarios/WizardAsView.cs index b7a0b6d0ba..49b70765b4 100644 --- a/UICatalog/Scenarios/WizardAsView.cs +++ b/UICatalog/Scenarios/WizardAsView.cs @@ -59,13 +59,13 @@ public override void Init () }; // Add 1st step - var firstStep = new Wizard.WizardStep () { Title = "End User License Agreement" }; + var firstStep = new WizardStep () { Title = "End User License Agreement" }; wizard.AddStep (firstStep); firstStep.NextButtonText = "Accept!"; firstStep.HelpText = "This is the End User License Agreement.\n\n\n\n\n\nThis is a test of the emergency broadcast system. This is a test of the emergency broadcast system.\nThis is a test of the emergency broadcast system.\n\n\nThis is a test of the emergency broadcast system.\n\nThis is a test of the emergency broadcast system.\n\n\n\nThe end of the EULA."; // Add 2nd step - var secondStep = new Wizard.WizardStep () { Title = "Second Step" }; + var secondStep = new WizardStep () { Title = "Second Step" }; wizard.AddStep (secondStep); secondStep.HelpText = "This is the help text for the Second Step.\n\nPress the button to change the Title.\n\nIf First Name is empty the step will prevent moving to the next step."; @@ -88,7 +88,7 @@ public override void Init () secondStep.Add (lbl, lastNameField); // Add last step - var lastStep = new Wizard.WizardStep () { Title = "The last step" }; + var lastStep = new WizardStep () { Title = "The last step" }; wizard.AddStep (lastStep); lastStep.HelpText = "The wizard is complete!\n\nPress the Finish button to continue.\n\nPressing Esc will cancel."; diff --git a/UICatalog/Scenarios/Wizards.cs b/UICatalog/Scenarios/Wizards.cs index e3a3380ca4..82fee4ea5e 100644 --- a/UICatalog/Scenarios/Wizards.cs +++ b/UICatalog/Scenarios/Wizards.cs @@ -137,13 +137,13 @@ void Top_Loaded (object sender, EventArgs args) }; // Add 1st step - var firstStep = new Wizard.WizardStep () { Title = "End User License Agreement"}; + var firstStep = new WizardStep () { Title = "End User License Agreement"}; firstStep.NextButtonText = "Accept!"; firstStep.HelpText = "This is the End User License Agreement.\n\n\n\n\n\nThis is a test of the emergency broadcast system. This is a test of the emergency broadcast system.\nThis is a test of the emergency broadcast system.\n\n\nThis is a test of the emergency broadcast system.\n\nThis is a test of the emergency broadcast system.\n\n\n\nThe end of the EULA."; wizard.AddStep (firstStep); // Add 2nd step - var secondStep = new Wizard.WizardStep () { Title = "Second Step" }; + var secondStep = new WizardStep () { Title = "Second Step" }; wizard.AddStep (secondStep); secondStep.HelpText = "This is the help text for the Second Step.\n\nPress the button to change the Title.\n\nIf First Name is empty the step will prevent moving to the next step."; @@ -184,7 +184,7 @@ void Top_Loaded (object sender, EventArgs args) }; // Add 3rd (optional) step - var thirdStep = new Wizard.WizardStep () { Title = "Third Step (Optional)" }; + var thirdStep = new WizardStep () { Title = "Third Step (Optional)" }; wizard.AddStep (thirdStep); thirdStep.HelpText = "This is step is optional (WizardStep.Enabled = false). Enable it with the checkbox in Step 2."; var step3Label = new Label () { @@ -207,7 +207,7 @@ void Top_Loaded (object sender, EventArgs args) }; // Add 4th step - var fourthStep = new Wizard.WizardStep () { Title = "Step Four" }; + var fourthStep = new WizardStep () { Title = "Step Four" }; wizard.AddStep (fourthStep); var someText = new TextView () { Text = "This step (Step Four) shows how to show/hide the Help pane. The step contains this TextView (but it's hard to tell it's a TextView because of Issue #1800).", @@ -266,14 +266,14 @@ void Top_Loaded (object sender, EventArgs args) fourthStep.Add (scrollBar); // Add last step - var lastStep = new Wizard.WizardStep () { Title = "The last step" }; + var lastStep = new WizardStep () { Title = "The last step" }; wizard.AddStep (lastStep); lastStep.HelpText = "The wizard is complete!\n\nPress the Finish button to continue.\n\nPressing ESC will cancel the wizard."; var finalFinalStepEnabledCeckBox = new CheckBox () { Text = "Enable _Final Final Step", Checked = false, X = 0, Y = 1 }; lastStep.Add (finalFinalStepEnabledCeckBox); // Add an optional FINAL last step - var finalFinalStep = new Wizard.WizardStep () { Title = "The VERY last step" }; + var finalFinalStep = new WizardStep () { Title = "The VERY last step" }; wizard.AddStep (finalFinalStep); finalFinalStep.HelpText = "This step only shows if it was enabled on the other last step."; finalFinalStep.Enabled = (bool)thirdStepEnabledCeckBox.Checked; diff --git a/UnitTests/Application/MainLoopTests.cs b/UnitTests/Application/MainLoopTests.cs index 36915f712d..e5b694f870 100644 --- a/UnitTests/Application/MainLoopTests.cs +++ b/UnitTests/Application/MainLoopTests.cs @@ -507,7 +507,7 @@ public void Internal_Tests () var mainloop = new MainLoop (testMainloop); Assert.Empty (mainloop.timeouts); Assert.Empty (mainloop.idleHandlers); - Assert.NotNull (new MainLoop.Timeout () { + Assert.NotNull (new Timeout () { Span = new TimeSpan (), Callback = (_) => true }); diff --git a/UnitTests/Dialogs/WizardTests.cs b/UnitTests/Dialogs/WizardTests.cs index 917bc52407..04bfbdef2c 100644 --- a/UnitTests/Dialogs/WizardTests.cs +++ b/UnitTests/Dialogs/WizardTests.cs @@ -159,7 +159,7 @@ public void OneStepWizard_Shows () var bottomRow = $"{CM.Glyphs.LLCornerDbl}{new string (CM.Glyphs.HLineDbl.ToString () [0], width - 2)}{CM.Glyphs.LRCornerDbl}"; var wizard = new Wizard () { Title = title, Width = width, Height = height }; - wizard.AddStep (new Wizard.WizardStep () { Title = stepTitle }); + wizard.AddStep (new WizardStep () { Title = stepTitle }); //wizard.LayoutSubviews (); var firstIteration = false; var runstate = Application.Begin (wizard); @@ -229,7 +229,7 @@ public void Setting_Title_Works () var bottomRow = $"{CM.Glyphs.LLCornerDbl}{new string (CM.Glyphs.HLineDbl.ToString () [0], width - 2)}{CM.Glyphs.LRCornerDbl}"; var wizard = new Wizard () { Title = title, Width = width, Height = height }; - wizard.AddStep (new Wizard.WizardStep () { Title = "ABCD" }); + wizard.AddStep (new WizardStep () { Title = "ABCD" }); Application.End (Application.Begin (wizard)); TestHelpers.AssertDriverContentsWithFrameAre ($"{topRow}\n{separatorRow}\n{buttonRow}\n{bottomRow}", output); @@ -243,7 +243,7 @@ public void Navigate_GetPreviousStep_Correct () // If no steps should be null Assert.Null (wizard.GetPreviousStep ()); - var step1 = new Wizard.WizardStep () { Title = "step1" }; + var step1 = new WizardStep () { Title = "step1" }; wizard.AddStep (step1); // If no current step, should be last step @@ -258,7 +258,7 @@ public void Navigate_GetPreviousStep_Correct () Assert.Null (wizard.GetPreviousStep ()); // If two steps and at 2 and step 1 is `Enabled = true`should be step1 - var step2 = new Wizard.WizardStep () { Title = "step2" }; + var step2 = new WizardStep () { Title = "step2" }; wizard.AddStep (step2); wizard.CurrentStep = step2; step1.Enabled = true; @@ -272,7 +272,7 @@ public void Navigate_GetPreviousStep_Correct () // At step 1 should be null // At step 2 should be step 1 // At step 3 should be step 2 - var step3 = new Wizard.WizardStep () { Title = "step3" }; + var step3 = new WizardStep () { Title = "step3" }; wizard.AddStep (step3); step1.Enabled = true; wizard.CurrentStep = step1; @@ -334,7 +334,7 @@ public void Navigate_GetNextStep_Correct () // If no steps should be null Assert.Null (wizard.GetNextStep ()); - var step1 = new Wizard.WizardStep () { Title = "step1" }; + var step1 = new WizardStep () { Title = "step1" }; wizard.AddStep (step1); // If no current step, should be first step @@ -349,7 +349,7 @@ public void Navigate_GetNextStep_Correct () Assert.Null (wizard.GetNextStep ()); // If two steps and at 1 and step 2 is `Enabled = true`should be step 2 - var step2 = new Wizard.WizardStep () { Title = "step2" }; + var step2 = new WizardStep () { Title = "step2" }; wizard.AddStep (step2); Assert.Equal (step2.Title, wizard.GetNextStep ().Title); @@ -363,7 +363,7 @@ public void Navigate_GetNextStep_Correct () // At step 1 should be step 2 // At step 2 should be step 3 // At step 3 should be null - var step3 = new Wizard.WizardStep () { Title = "step3" }; + var step3 = new WizardStep () { Title = "step3" }; wizard.AddStep (step3); step1.Enabled = true; wizard.CurrentStep = step1; @@ -457,15 +457,15 @@ public void Navigate_GetFirstStep_Works () Assert.Null (wizard.GetFirstStep ()); - var step1 = new Wizard.WizardStep () { Title = "step1" }; + var step1 = new WizardStep () { Title = "step1" }; wizard.AddStep (step1); Assert.Equal (step1.Title, wizard.GetFirstStep ().Title); - var step2 = new Wizard.WizardStep () { Title = "step2" }; + var step2 = new WizardStep () { Title = "step2" }; wizard.AddStep (step2); Assert.Equal (step1.Title, wizard.GetFirstStep ().Title); - var step3 = new Wizard.WizardStep () { Title = "step3" }; + var step3 = new WizardStep () { Title = "step3" }; wizard.AddStep (step3); Assert.Equal (step1.Title, wizard.GetFirstStep ().Title); @@ -487,15 +487,15 @@ public void Navigate_GetLastStep_Works () Assert.Null (wizard.GetLastStep ()); - var step1 = new Wizard.WizardStep () { Title = "step1" }; + var step1 = new WizardStep () { Title = "step1" }; wizard.AddStep (step1); Assert.Equal (step1.Title, wizard.GetLastStep ().Title); - var step2 = new Wizard.WizardStep () { Title = "step2" }; + var step2 = new WizardStep () { Title = "step2" }; wizard.AddStep (step2); Assert.Equal (step2.Title, wizard.GetLastStep ().Title); - var step3 = new Wizard.WizardStep () { Title = "step3" }; + var step3 = new WizardStep () { Title = "step3" }; wizard.AddStep (step3); Assert.Equal (step3.Title, wizard.GetLastStep ().Title); @@ -515,7 +515,7 @@ public void Finish_Button_Closes () { // https://github.com/gui-cs/Terminal.Gui/issues/1833 var wizard = new Wizard (); - var step1 = new Wizard.WizardStep () { Title = "step1" }; + var step1 = new WizardStep () { Title = "step1" }; wizard.AddStep (step1); var finishedFired = false; @@ -543,9 +543,9 @@ public void Finish_Button_Closes () // Same test, but with two steps wizard = new Wizard (); firstIteration = false; - step1 = new Wizard.WizardStep () { Title = "step1" }; + step1 = new WizardStep () { Title = "step1" }; wizard.AddStep (step1); - var step2 = new Wizard.WizardStep () { Title = "step2" }; + var step2 = new WizardStep () { Title = "step2" }; wizard.AddStep (step2); finishedFired = false; @@ -580,9 +580,9 @@ public void Finish_Button_Closes () // Same test, but with two steps but the 1st one disabled wizard = new Wizard (); firstIteration = false; - step1 = new Wizard.WizardStep () { Title = "step1" }; + step1 = new WizardStep () { Title = "step1" }; wizard.AddStep (step1); - step2 = new Wizard.WizardStep () { Title = "step2" }; + step2 = new WizardStep () { Title = "step2" }; wizard.AddStep (step2); step1.Enabled = false; diff --git a/UnitTests/Views/GraphViewTests.cs b/UnitTests/Views/GraphViewTests.cs index b954632b84..7794d3540b 100644 --- a/UnitTests/Views/GraphViewTests.cs +++ b/UnitTests/Views/GraphViewTests.cs @@ -711,7 +711,7 @@ public void TestZeroHeightBar_WithName () Assert.Empty (axisY.LabelPoints); // bar of height 0 - barSeries.Bars.Add (new BarSeries.Bar ("hi", new GraphCellToRender ((Rune)'.'), 0)); + barSeries.Bars.Add (new Bar ("hi", new GraphCellToRender ((Rune)'.'), 0)); barSeries.Orientation = Orientation.Vertical; // redraw graph @@ -753,9 +753,9 @@ public void TestTwoTallBars_WithOffset () barSeries.BarEvery = 1f; barSeries.Bars.Add ( - new BarSeries.Bar ("hi1", new GraphCellToRender ((Rune)'.'), 100)); + new Bar ("hi1", new GraphCellToRender ((Rune)'.'), 100)); barSeries.Bars.Add ( - new BarSeries.Bar ("hi2", new GraphCellToRender ((Rune)'.'), 100)); + new Bar ("hi2", new GraphCellToRender ((Rune)'.'), 100)); barSeries.Orientation = Orientation.Vertical; @@ -809,11 +809,11 @@ public void TestOneLongOneShortHorizontalBars_WithOffset () // 1 bar that is very wide (100 graph units horizontally = screen pos 50 but bounded by screen) barSeries.Bars.Add ( - new BarSeries.Bar ("hi1", new GraphCellToRender ((Rune)'.'), 100)); + new Bar ("hi1", new GraphCellToRender ((Rune)'.'), 100)); // 1 bar that is shorter barSeries.Bars.Add ( - new BarSeries.Bar ("hi2", new GraphCellToRender ((Rune)'.'), 5)); + new Bar ("hi2", new GraphCellToRender ((Rune)'.'), 5)); // redraw graph graph.Draw (); diff --git a/UnitTests/Views/TableViewTests.cs b/UnitTests/Views/TableViewTests.cs index ad34e26f03..3b8d10bab9 100644 --- a/UnitTests/Views/TableViewTests.cs +++ b/UnitTests/Views/TableViewTests.cs @@ -2999,7 +2999,7 @@ public void TestListTableSource (Orientation orient, bool parallel) ShowHorizontalHeaderOverline = false, ShowHorizontalHeaderUnderline = false }; - var listStyle = new ListTableSource.ListColumnStyle () { + var listStyle = new ListColumnStyle () { Orientation = orient, ScrollParallel = parallel }; From 0a6baa97c05f992b3a3ba29580a5b0d9a8d1b962 Mon Sep 17 00:00:00 2001 From: tznind Date: Mon, 22 May 2023 19:54:50 +0100 Subject: [PATCH 2/9] Move more nested classes out --- Terminal.Gui/Terminal.Gui.csproj | 1 + Terminal.Gui/Views/GraphView/Bar.cs | 2 +- Terminal.Gui/Views/GraphView/Series.cs | 2 +- Terminal.Gui/Views/TableView/ColumnStyle.cs | 104 +++++++ .../Views/TableView/ListColumnStyle.cs | 2 +- .../Views/TableView/TableSelection.cs | 37 +++ Terminal.Gui/Views/TableView/TableStyle.cs | 135 ++++++++ Terminal.Gui/Views/TableView/TableView.cs | 294 +----------------- UICatalog/Scenarios/TableEditor.cs | 8 +- UnitTests/Views/TableViewTests.cs | 8 +- 10 files changed, 303 insertions(+), 290 deletions(-) create mode 100644 Terminal.Gui/Views/TableView/ColumnStyle.cs create mode 100644 Terminal.Gui/Views/TableView/TableSelection.cs create mode 100644 Terminal.Gui/Views/TableView/TableStyle.cs diff --git a/Terminal.Gui/Terminal.Gui.csproj b/Terminal.Gui/Terminal.Gui.csproj index 9f9e582b67..0cd7977bc6 100644 --- a/Terminal.Gui/Terminal.Gui.csproj +++ b/Terminal.Gui/Terminal.Gui.csproj @@ -5,6 +5,7 @@ TRACE;DEBUG_IDISPOSABLE portable + 4 diff --git a/Terminal.Gui/Views/GraphView/Bar.cs b/Terminal.Gui/Views/GraphView/Bar.cs index d1b40d3279..c98a86e7c7 100644 --- a/Terminal.Gui/Views/GraphView/Bar.cs +++ b/Terminal.Gui/Views/GraphView/Bar.cs @@ -7,7 +7,7 @@ public class Bar { /// /// Optional text that describes the bar. This will be rendered on the corresponding - /// unless is false + /// unless is false /// public string Text { get; set; } diff --git a/Terminal.Gui/Views/GraphView/Series.cs b/Terminal.Gui/Views/GraphView/Series.cs index a5d50a8da5..537fc3fe30 100644 --- a/Terminal.Gui/Views/GraphView/Series.cs +++ b/Terminal.Gui/Views/GraphView/Series.cs @@ -72,7 +72,7 @@ public class MultiBarSeries : ISeries { /// /// The number of units of graph space between bars. Should be - /// less than + /// less than /// public float Spacing { get; } diff --git a/Terminal.Gui/Views/TableView/ColumnStyle.cs b/Terminal.Gui/Views/TableView/ColumnStyle.cs new file mode 100644 index 0000000000..a55d5f7042 --- /dev/null +++ b/Terminal.Gui/Views/TableView/ColumnStyle.cs @@ -0,0 +1,104 @@ +using System; + +namespace Terminal.Gui { + + /// + /// Describes how to render a given column in a including + /// and textual representation of cells (e.g. date formats) + /// + /// See TableView Deep Dive for more information. + /// + public class ColumnStyle { + + /// + /// Defines the default alignment for all values rendered in this column. For custom alignment based on cell contents use . + /// + public TextAlignment Alignment { get; set; } + + /// + /// Defines a delegate for returning custom alignment per cell based on cell values. When specified this will override + /// + public Func AlignmentGetter; + + /// + /// Defines a delegate for returning custom representations of cell values. If not set then is used. Return values from your delegate may be truncated e.g. based on + /// + public Func RepresentationGetter; + + /// + /// Defines a delegate for returning a custom color scheme per cell based on cell values. + /// Return null for the default + /// + public CellColorGetterDelegate ColorGetter; + private bool visible = true; + + /// + /// Defines the format for values e.g. "yyyy-MM-dd" for dates + /// + public string Format { get; set; } + + /// + /// Set the maximum width of the column in characters. This value will be ignored if more than the tables . Defaults to + /// + public int MaxWidth { get; set; } = TableView.DefaultMaxCellWidth; + + /// + /// Set the minimum width of the column in characters. Setting this will ensure that + /// even when a column has short content/header it still fills a given width of the control. + /// + /// This value will be ignored if more than the tables + /// or the + /// + /// + /// For setting a flexible column width (down to a lower limit) use + /// instead + /// + /// + public int MinWidth { get; set; } + + /// + /// Enables flexible sizing of this column based on available screen space to render into. + /// + public int MinAcceptableWidth { get; set; } = TableView.DefaultMinAcceptableWidth; + + /// + /// Gets or Sets a value indicating whether the column should be visible to the user. + /// This affects both whether it is rendered and whether it can be selected. Defaults to + /// true. + /// + /// If is 0 then will always return false. + public bool Visible { get => MaxWidth >= 0 && visible; set => visible = value; } + + /// + /// Returns the alignment for the cell based on and / + /// + /// + /// + public TextAlignment GetAlignment (object cellValue) + { + if (AlignmentGetter != null) + return AlignmentGetter (cellValue); + + return Alignment; + } + + /// + /// Returns the full string to render (which may be truncated if too long) that the current style says best represents the given + /// + /// + /// + public string GetRepresentation (object value) + { + if (!string.IsNullOrWhiteSpace (Format)) { + + if (value is IFormattable f) + return f.ToString (Format, null); + } + + if (RepresentationGetter != null) + return RepresentationGetter (value); + + return value?.ToString (); + } + } +} \ No newline at end of file diff --git a/Terminal.Gui/Views/TableView/ListColumnStyle.cs b/Terminal.Gui/Views/TableView/ListColumnStyle.cs index 76421ccac5..3bf5b55856 100644 --- a/Terminal.Gui/Views/TableView/ListColumnStyle.cs +++ b/Terminal.Gui/Views/TableView/ListColumnStyle.cs @@ -11,7 +11,7 @@ public class ListColumnStyle { public Orientation Orientation { get; set; } = Orientation.Horizontal; /// - /// Gets or sets a flag indicating whether to scroll in the same direction as . + /// Gets or sets a flag indicating whether to scroll in the same direction as . /// Defaults to . /// public bool ScrollParallel { get; set; } = false; diff --git a/Terminal.Gui/Views/TableView/TableSelection.cs b/Terminal.Gui/Views/TableView/TableSelection.cs new file mode 100644 index 0000000000..89a2290bd1 --- /dev/null +++ b/Terminal.Gui/Views/TableView/TableSelection.cs @@ -0,0 +1,37 @@ +namespace Terminal.Gui { + + /// + /// Describes a selected region of the table + /// + public class TableSelection { + + /// + /// Corner of the where selection began + /// + /// + public Point Origin { get; set; } + + /// + /// Area selected + /// + /// + public Rect Rect { get; set; } + + /// + /// True if the selection was made through + /// and therefore should persist even through keyboard navigation. + /// + public bool IsToggled { get; set; } + + /// + /// Creates a new selected area starting at the origin corner and covering the provided rectangular area + /// + /// + /// + public TableSelection (Point origin, Rect rect) + { + Origin = origin; + Rect = rect; + } + } +} \ No newline at end of file diff --git a/Terminal.Gui/Views/TableView/TableStyle.cs b/Terminal.Gui/Views/TableView/TableStyle.cs new file mode 100644 index 0000000000..bb216bf9f8 --- /dev/null +++ b/Terminal.Gui/Views/TableView/TableStyle.cs @@ -0,0 +1,135 @@ +using System.Collections.Generic; + +namespace Terminal.Gui { + + public partial class TableView { + /// + /// Defines rendering options that affect how the table is displayed. + /// + /// See TableView Deep Dive for more information. + /// + public class TableStyle { + + /// + /// Gets or sets a flag indicating whether to render headers of a . + /// Defaults to . + /// + /// , etc + /// may still be used even if is . + public bool ShowHeaders { get; set; } = true; + + /// + /// When scrolling down always lock the column headers in place as the first row of the table + /// + public bool AlwaysShowHeaders { get; set; } = false; + + /// + /// True to render a solid line above the headers + /// + public bool ShowHorizontalHeaderOverline { get; set; } = true; + + /// + /// True to render a solid line under the headers + /// + public bool ShowHorizontalHeaderUnderline { get; set; } = true; + + /// + /// True to render a solid line vertical line between cells + /// + public bool ShowVerticalCellLines { get; set; } = true; + + /// + /// True to render a solid line vertical line between headers + /// + public bool ShowVerticalHeaderLines { get; set; } = true; + + /// + /// True to render a arrows on the right/left of the table when + /// there are more column(s) that can be scrolled to. Requires + /// to be true. + /// Defaults to true + /// + public bool ShowHorizontalScrollIndicators { get; set; } = true; + + + /// + /// Gets or sets a flag indicating whether there should be a horizontal line after all the data + /// in the table. Defaults to . + /// + public bool ShowHorizontalBottomline { get; set; } = false; + + /// + /// True to invert the colors of the first symbol of the selected cell in the . + /// This gives the appearance of a cursor for when the doesn't otherwise show + /// this + /// + public bool InvertSelectedCellFirstCharacter { get; set; } = false; + + /// + /// Gets or sets a flag indicating whether to force use when rendering + /// vertical cell lines (even when is on). + /// + public bool AlwaysUseNormalColorForVerticalCellLines { get; set; } = false; + + /// + /// Collection of columns for which you want special rendering (e.g. custom column lengths, text alignment etc) + /// + public Dictionary ColumnStyles { get; set; } = new Dictionary (); + + /// + /// Delegate for coloring specific rows in a different color. For cell color + /// + /// + public RowColorGetterDelegate RowColorGetter { get; set; } + + /// + /// Determines rendering when the last column in the table is visible but it's + /// content or is less than the remaining + /// space in the control. True (the default) will expand the column to fill + /// the remaining bounds of the control. False will draw a column ending line + /// and leave a blank column that cannot be selected in the remaining space. + /// + /// + public bool ExpandLastColumn { get; set; } = true; + + /// + /// + /// Determines how is updated when scrolling + /// right off the end of the currently visible area. + /// + /// + /// If true then when scrolling right the scroll offset is increased the minimum required to show + /// the new column. This may be slow if you have an incredibly large number of columns in + /// your table and/or slow implementations + /// + /// + /// If false then scroll offset is set to the currently selected column (i.e. PageRight). + /// + /// + public bool SmoothHorizontalScrolling { get; set; } = true; + + /// + /// Returns the entry from for the given or null if no custom styling is defined for it + /// + /// + /// + public ColumnStyle GetColumnStyleIfAny (int col) + { + return ColumnStyles.TryGetValue (col, out ColumnStyle result) ? result : null; + } + + /// + /// Returns an existing for the given or creates a new one with default options + /// + /// + /// + public ColumnStyle GetOrCreateColumnStyle (int col) + { + if (!ColumnStyles.ContainsKey (col)) + ColumnStyles.Add (col, new ColumnStyle ()); + + return ColumnStyles [col]; + } + } + } +} \ No newline at end of file diff --git a/Terminal.Gui/Views/TableView/TableView.cs b/Terminal.Gui/Views/TableView/TableView.cs index c9d9dcee5f..760d5759ee 100644 --- a/Terminal.Gui/Views/TableView/TableView.cs +++ b/Terminal.Gui/Views/TableView/TableView.cs @@ -4,10 +4,23 @@ using System.Collections.Generic; using System.Data; using System.Linq; -using static Terminal.Gui.SpinnerStyle; namespace Terminal.Gui { + /// + /// Delegate for providing color to cells based on the value being rendered + /// + /// Contains information about the cell for which color is needed + /// + public delegate ColorScheme CellColorGetterDelegate (CellColorGetterArgs args); + + /// + /// Delegate for providing color for a whole row of a + /// + /// + /// + public delegate ColorScheme RowColorGetterDelegate (RowColorGetterArgs args); + /// /// View for tabular data based on a . /// @@ -1767,248 +1780,7 @@ private string GetRepresentation (object value, ColumnStyle colStyle) return colStyle != null ? colStyle.GetRepresentation (value) : value.ToString (); } - /// - /// Delegate for providing color to cells based on the value being rendered - /// - /// Contains information about the cell for which color is needed - /// - public delegate ColorScheme CellColorGetterDelegate (CellColorGetterArgs args); - - /// - /// Delegate for providing color for a whole row of a - /// - /// - /// - public delegate ColorScheme RowColorGetterDelegate (RowColorGetterArgs args); - - #region Nested Types - /// - /// Describes how to render a given column in a including - /// and textual representation of cells (e.g. date formats) - /// - /// See TableView Deep Dive for more information. - /// - public class ColumnStyle { - - /// - /// Defines the default alignment for all values rendered in this column. For custom alignment based on cell contents use . - /// - public TextAlignment Alignment { get; set; } - - /// - /// Defines a delegate for returning custom alignment per cell based on cell values. When specified this will override - /// - public Func AlignmentGetter; - - /// - /// Defines a delegate for returning custom representations of cell values. If not set then is used. Return values from your delegate may be truncated e.g. based on - /// - public Func RepresentationGetter; - - /// - /// Defines a delegate for returning a custom color scheme per cell based on cell values. - /// Return null for the default - /// - public CellColorGetterDelegate ColorGetter; - private bool visible = true; - - /// - /// Defines the format for values e.g. "yyyy-MM-dd" for dates - /// - public string Format { get; set; } - - /// - /// Set the maximum width of the column in characters. This value will be ignored if more than the tables . Defaults to - /// - public int MaxWidth { get; set; } = TableView.DefaultMaxCellWidth; - - /// - /// Set the minimum width of the column in characters. Setting this will ensure that - /// even when a column has short content/header it still fills a given width of the control. - /// - /// This value will be ignored if more than the tables - /// or the - /// - /// - /// For setting a flexible column width (down to a lower limit) use - /// instead - /// - /// - public int MinWidth { get; set; } - - /// - /// Enables flexible sizing of this column based on available screen space to render into. - /// - public int MinAcceptableWidth { get; set; } = DefaultMinAcceptableWidth; - - /// - /// Gets or Sets a value indicating whether the column should be visible to the user. - /// This affects both whether it is rendered and whether it can be selected. Defaults to - /// true. - /// - /// If is 0 then will always return false. - public bool Visible { get => MaxWidth >= 0 && visible; set => visible = value; } - - /// - /// Returns the alignment for the cell based on and / - /// - /// - /// - public TextAlignment GetAlignment (object cellValue) - { - if (AlignmentGetter != null) - return AlignmentGetter (cellValue); - - return Alignment; - } - - /// - /// Returns the full string to render (which may be truncated if too long) that the current style says best represents the given - /// - /// - /// - public string GetRepresentation (object value) - { - if (!string.IsNullOrWhiteSpace (Format)) { - - if (value is IFormattable f) - return f.ToString (Format, null); - } - - if (RepresentationGetter != null) - return RepresentationGetter (value); - - return value?.ToString (); - } - } - /// - /// Defines rendering options that affect how the table is displayed. - /// - /// See TableView Deep Dive for more information. - /// - public class TableStyle { - - /// - /// Gets or sets a flag indicating whether to render headers of a . - /// Defaults to . - /// - /// , etc - /// may still be used even if is . - public bool ShowHeaders { get; set; } = true; - - /// - /// When scrolling down always lock the column headers in place as the first row of the table - /// - public bool AlwaysShowHeaders { get; set; } = false; - - /// - /// True to render a solid line above the headers - /// - public bool ShowHorizontalHeaderOverline { get; set; } = true; - - /// - /// True to render a solid line under the headers - /// - public bool ShowHorizontalHeaderUnderline { get; set; } = true; - - /// - /// True to render a solid line vertical line between cells - /// - public bool ShowVerticalCellLines { get; set; } = true; - - /// - /// True to render a solid line vertical line between headers - /// - public bool ShowVerticalHeaderLines { get; set; } = true; - - /// - /// True to render a arrows on the right/left of the table when - /// there are more column(s) that can be scrolled to. Requires - /// to be true. - /// Defaults to true - /// - public bool ShowHorizontalScrollIndicators { get; set; } = true; - - - /// - /// Gets or sets a flag indicating whether there should be a horizontal line after all the data - /// in the table. Defaults to . - /// - public bool ShowHorizontalBottomline { get; set; } = false; - - /// - /// True to invert the colors of the first symbol of the selected cell in the . - /// This gives the appearance of a cursor for when the doesn't otherwise show - /// this - /// - public bool InvertSelectedCellFirstCharacter { get; set; } = false; - - /// - /// Gets or sets a flag indicating whether to force use when rendering - /// vertical cell lines (even when is on). - /// - public bool AlwaysUseNormalColorForVerticalCellLines { get; set; } = false; - - /// - /// Collection of columns for which you want special rendering (e.g. custom column lengths, text alignment etc) - /// - public Dictionary ColumnStyles { get; set; } = new Dictionary (); - - /// - /// Delegate for coloring specific rows in a different color. For cell color - /// - /// - public RowColorGetterDelegate RowColorGetter { get; set; } - - /// - /// Determines rendering when the last column in the table is visible but it's - /// content or is less than the remaining - /// space in the control. True (the default) will expand the column to fill - /// the remaining bounds of the control. False will draw a column ending line - /// and leave a blank column that cannot be selected in the remaining space. - /// - /// - public bool ExpandLastColumn { get; set; } = true; - - /// - /// - /// Determines how is updated when scrolling - /// right off the end of the currently visible area. - /// - /// - /// If true then when scrolling right the scroll offset is increased the minimum required to show - /// the new column. This may be slow if you have an incredibly large number of columns in - /// your table and/or slow implementations - /// - /// - /// If false then scroll offset is set to the currently selected column (i.e. PageRight). - /// - /// - public bool SmoothHorizontalScrolling { get; set; } = true; - - /// - /// Returns the entry from for the given or null if no custom styling is defined for it - /// - /// - /// - public ColumnStyle GetColumnStyleIfAny (int col) - { - return ColumnStyles.TryGetValue (col, out ColumnStyle result) ? result : null; - } - - /// - /// Returns an existing for the given or creates a new one with default options - /// - /// - /// - public ColumnStyle GetOrCreateColumnStyle (int col) - { - if (!ColumnStyles.ContainsKey (col)) - ColumnStyles.Add (col, new ColumnStyle ()); - - return ColumnStyles [col]; - } - } + /// /// Describes a desire to render a column at a given horizontal position in the UI @@ -2045,41 +1817,5 @@ public ColumnToRender (int col, int x, int width, bool isVeryLast) } } - - /// - /// Describes a selected region of the table - /// - public class TableSelection { - - /// - /// Corner of the where selection began - /// - /// - public Point Origin { get; set; } - - /// - /// Area selected - /// - /// - public Rect Rect { get; set; } - - /// - /// True if the selection was made through - /// and therefore should persist even through keyboard navigation. - /// - public bool IsToggled { get; set; } - - /// - /// Creates a new selected area starting at the origin corner and covering the provided rectangular area - /// - /// - /// - public TableSelection (Point origin, Rect rect) - { - Origin = origin; - Rect = rect; - } - } - #endregion } } \ No newline at end of file diff --git a/UICatalog/Scenarios/TableEditor.cs b/UICatalog/Scenarios/TableEditor.cs index 30aaa42f5a..19b55eb7bd 100644 --- a/UICatalog/Scenarios/TableEditor.cs +++ b/UICatalog/Scenarios/TableEditor.cs @@ -793,19 +793,19 @@ private void SetDemoTableStyles () { tableView.Style.ColumnStyles.Clear(); - var alignMid = new TableView.ColumnStyle () { + var alignMid = new ColumnStyle () { Alignment = TextAlignment.Centered }; - var alignRight = new TableView.ColumnStyle () { + var alignRight = new ColumnStyle () { Alignment = TextAlignment.Right }; - var dateFormatStyle = new TableView.ColumnStyle () { + var dateFormatStyle = new ColumnStyle () { Alignment = TextAlignment.Right, RepresentationGetter = (v) => v is DateTime d ? d.ToString ("yyyy-MM-dd") : v.ToString () }; - var negativeRight = new TableView.ColumnStyle () { + var negativeRight = new ColumnStyle () { Format = "0.##", MinWidth = 10, diff --git a/UnitTests/Views/TableViewTests.cs b/UnitTests/Views/TableViewTests.cs index 3b8d10bab9..d179adef69 100644 --- a/UnitTests/Views/TableViewTests.cs +++ b/UnitTests/Views/TableViewTests.cs @@ -327,7 +327,7 @@ public void DeleteRow_SelectLastRow_AdjustsSelectionToPreventOverrun () // select the last row tableView.MultiSelectedRegions.Clear (); - tableView.MultiSelectedRegions.Push (new TableView.TableSelection (new Point (0, 3), new Rect (0, 3, 4, 1))); + tableView.MultiSelectedRegions.Push (new TableSelection (new Point (0, 3), new Rect (0, 3, 4, 1))); Assert.Equal (4, tableView.GetAllSelectedCells ().Count ()); @@ -430,8 +430,8 @@ public void GetAllSelectedCells_TwoIsolatedSelections_ReturnsSix () */ tableView.MultiSelectedRegions.Clear (); - tableView.MultiSelectedRegions.Push (new TableView.TableSelection (new Point (1, 1), new Rect (1, 1, 2, 2))); - tableView.MultiSelectedRegions.Push (new TableView.TableSelection (new Point (7, 3), new Rect (7, 3, 2, 1))); + tableView.MultiSelectedRegions.Push (new TableSelection (new Point (1, 1), new Rect (1, 1, 2, 2))); + tableView.MultiSelectedRegions.Push (new TableSelection (new Point (7, 3), new Rect (7, 3, 2, 1))); tableView.SelectedColumn = 8; tableView.SelectedRow = 3; @@ -1534,7 +1534,7 @@ public void TestColumnStyle_VisibleFalse_MultiSelected () // user has rectangular selection tableView.MultiSelectedRegions.Push ( - new TableView.TableSelection ( + new TableSelection ( new Point (0, 0), new Rect (0, 0, 3, 1)) ); From 915ec1bb74cfbf796bc38e8d7251fe527d7f92c9 Mon Sep 17 00:00:00 2001 From: tznind Date: Mon, 22 May 2023 20:23:29 +0100 Subject: [PATCH 3/9] Tidy up and treat CA1034 as an error. Fix remaining nested classes. --- Terminal.Gui/Application.cs | 109 +------ Terminal.Gui/ApplicationRunState.cs | 79 +++++ Terminal.Gui/Configuration/ThemeManager.cs | 209 ++++++++++++ Terminal.Gui/Configuration/ThemeScope.cs | 303 +++--------------- .../CursesDriver/CursesMouseEvent.cs | 67 ++++ .../ConsoleDrivers/CursesDriver/binding.cs | 22 +- .../FakeDriver/FakeClipboard.cs | 46 +++ .../ConsoleDrivers/FakeDriver/FakeDriver.cs | 36 +-- Terminal.Gui/Drawing/LineCanvas.cs | 24 +- Terminal.Gui/Drawing/LineCanvasCell.cs | 21 ++ Terminal.Gui/FileServices/FileDialogStyle.cs | 2 +- Terminal.Gui/GlobalSuppressions.cs | 8 - Terminal.Gui/MainLoop.cs | 2 +- Terminal.Gui/RunStateEventArgs.cs | 6 +- Terminal.Gui/Terminal.Gui.csproj | 2 +- Terminal.Gui/Views/GraphView/Annotations.cs | 2 +- Terminal.Gui/Views/GraphView/Series.cs | 2 +- .../Views/SpinnerView/SpinnerStyle.cs | 6 +- Terminal.Gui/Views/Tab.cs | 40 +++ Terminal.Gui/Views/TabChangedEventArgs.cs | 6 +- Terminal.Gui/Views/TabMouseEventArgs.cs | 4 +- Terminal.Gui/Views/TabStyle.cs | 29 ++ Terminal.Gui/Views/TabView.cs | 70 +--- .../Views/TableView/ListTableSource.cs | 2 +- Terminal.Gui/Views/TableView/TableStyle.cs | 254 ++++++++------- Terminal.Gui/Views/TableView/TableView.cs | 2 +- Terminal.Gui/Views/TileView.cs | 2 +- Terminal.Gui/Views/Toplevel.cs | 30 +- Terminal.Gui/Views/Wizard/Wizard.cs | 2 +- UICatalog/Scenarios/Editor.cs | 4 +- UICatalog/Scenarios/Notepad.cs | 6 +- UICatalog/Scenarios/TabViewExample.cs | 16 +- UICatalog/UICatalog.cs | 4 +- UnitTests/Application/ApplicationTests.cs | 6 +- UnitTests/Application/RunStateTests.cs | 12 +- UnitTests/Configuration/AppScopeTests.cs | 2 +- UnitTests/Configuration/SettingsScopeTests.cs | 6 +- UnitTests/Configuration/ThemeScopeTests.cs | 18 +- UnitTests/Dialogs/DialogTests.cs | 24 +- UnitTests/View/Layout/PosTests.cs | 4 +- UnitTests/Views/ButtonTests.cs | 2 +- UnitTests/Views/OverlappedTests.cs | 2 +- UnitTests/Views/TabViewTests.cs | 52 +-- 43 files changed, 808 insertions(+), 737 deletions(-) create mode 100644 Terminal.Gui/ApplicationRunState.cs create mode 100644 Terminal.Gui/Configuration/ThemeManager.cs create mode 100644 Terminal.Gui/ConsoleDrivers/CursesDriver/CursesMouseEvent.cs create mode 100644 Terminal.Gui/ConsoleDrivers/FakeDriver/FakeClipboard.cs create mode 100644 Terminal.Gui/Drawing/LineCanvasCell.cs delete mode 100644 Terminal.Gui/GlobalSuppressions.cs create mode 100644 Terminal.Gui/Views/Tab.cs create mode 100644 Terminal.Gui/Views/TabStyle.cs diff --git a/Terminal.Gui/Application.cs b/Terminal.Gui/Application.cs index 929578fdad..d8871d53f5 100644 --- a/Terminal.Gui/Application.cs +++ b/Terminal.Gui/Application.cs @@ -304,115 +304,40 @@ static void ResetState () #region Run (Begin, Run, End) /// - /// Notify that a new was created ( was called). The token is created in + /// Notify that a new was created ( was called). The token is created in /// and this event will be fired before that function exits. /// /// /// If is callers to /// must also subscribe to - /// and manually dispose of the token when the application is done. + /// and manually dispose of the token when the application is done. /// public static event EventHandler NotifyNewRunState; /// - /// Notify that a existent is stopping ( was called). + /// Notify that a existent is stopping ( was called). /// /// /// If is callers to /// must also subscribe to - /// and manually dispose of the token when the application is done. + /// and manually dispose of the token when the application is done. /// public static event EventHandler NotifyStopRunState; - /// - /// The execution state for a view. - /// - public class RunState : IDisposable { - /// - /// Initializes a new class. - /// - /// - public RunState (Toplevel view) - { - Toplevel = view; - } - /// - /// The belonging to this . - /// - public Toplevel Toplevel { get; internal set; } - -#if DEBUG_IDISPOSABLE - /// - /// For debug (see DEBUG_IDISPOSABLE define) purposes to verify objects are being disposed properly - /// - public bool WasDisposed = false; - - /// - /// For debug (see DEBUG_IDISPOSABLE define) purposes to verify objects are being disposed properly - /// - public int DisposedCount = 0; - - /// - /// For debug (see DEBUG_IDISPOSABLE define) purposes; the runstate instances that have been created - /// - public static List Instances = new List (); - - /// - /// Creates a new RunState object. - /// - public RunState () - { - Instances.Add (this); - } -#endif - - /// - /// Releases all resource used by the object. - /// - /// - /// Call when you are finished using the . - /// - /// - /// method leaves the in an unusable state. After - /// calling , you must release all references to the - /// so the garbage collector can reclaim the memory that the - /// was occupying. - /// - public void Dispose () - { - Dispose (true); - GC.SuppressFinalize (this); -#if DEBUG_IDISPOSABLE - WasDisposed = true; -#endif - } - - /// - /// Releases all resource used by the object. - /// - /// If set to we are disposing and should dispose held objects. - protected virtual void Dispose (bool disposing) - { - if (Toplevel != null && disposing) { - throw new InvalidOperationException ("You must clean up (Dispose) the Toplevel before calling Application.RunState.Dispose"); - } - } - } - /// /// Building block API: Prepares the provided for execution. /// - /// The handle that needs to be passed to the method upon completion. + /// The handle that needs to be passed to the method upon completion. /// The to prepare execution for. /// /// This method prepares the provided for running with the focus, /// it adds this to the list of s, sets up the to process the /// event, lays out the Subviews, focuses the first element, and draws the /// in the screen. This is usually followed by executing - /// the method, and then the method upon termination which will + /// the method, and then the method upon termination which will /// undo these changes. /// - public static RunState Begin (Toplevel Toplevel) + public static ApplicationRunState Begin (Toplevel Toplevel) { if (Toplevel == null) { throw new ArgumentNullException (nameof (Toplevel)); @@ -423,7 +348,7 @@ public static RunState Begin (Toplevel Toplevel) // Ensure the mouse is ungrabed. _mouseGrabView = null; - var rs = new RunState (Toplevel); + var rs = new ApplicationRunState (Toplevel); // View implements ISupportInitializeNotification which is derived from ISupportInitialize if (!Toplevel.IsInitialized) { @@ -574,20 +499,20 @@ public static void Run (Func errorHandler = null) /// To make a stop execution, call . /// /// - /// Calling is equivalent to calling , followed by , - /// and then calling . + /// Calling is equivalent to calling , followed by , + /// and then calling . /// /// /// Alternatively, to have a program control the main loop and /// process events manually, call to set things up manually and then - /// repeatedly call with the wait parameter set to false. By doing this - /// the method will only process any pending events, timers, idle handlers and + /// repeatedly call with the wait parameter set to false. By doing this + /// the method will only process any pending events, timers, idle handlers and /// then return control immediately. /// /// /// RELEASE builds only: When is any exeptions will be rethrown. /// Otherwise, if will be called. If - /// returns the will resume; otherwise + /// returns the will resume; otherwise /// this method will exit. /// /// @@ -713,7 +638,7 @@ public override void Send (SendOrPostCallback d, object state) /// The state returned by the method. /// By default this is which will execute the loop waiting for events, /// if set to , a single iteration will execute. - public static void RunLoop (RunState state, bool wait = true) + public static void RunLoop (ApplicationRunState state, bool wait = true) { if (state == null) throw new ArgumentNullException (nameof (state)); @@ -737,7 +662,7 @@ public static void RunLoop (RunState state, bool wait = true) /// will return after a single iteration. /// Set to if this is the first run loop iteration. Upon return, /// it will be set to if at least one iteration happened. - public static void RunMainLoopIteration (ref RunState state, bool wait, ref bool firstIteration) + public static void RunMainLoopIteration (ref ApplicationRunState state, bool wait, ref bool firstIteration) { if (MainLoop.EventsPending (wait)) { // Notify Toplevel it's ready @@ -900,8 +825,8 @@ static void OnNotifyStopRunState (Toplevel top) /// /// Building block API: completes the execution of a that was started with . /// - /// The returned by the method. - public static void End (RunState runState) + /// The returned by the method. + public static void End (ApplicationRunState runState) { if (runState == null) throw new ArgumentNullException (nameof (runState)); diff --git a/Terminal.Gui/ApplicationRunState.cs b/Terminal.Gui/ApplicationRunState.cs new file mode 100644 index 0000000000..400248247d --- /dev/null +++ b/Terminal.Gui/ApplicationRunState.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; + +namespace Terminal.Gui { + /// + /// The execution state for a view. + /// + public class ApplicationRunState : IDisposable { + /// + /// Initializes a new class. + /// + /// + public ApplicationRunState (Toplevel view) + { + Toplevel = view; + } + /// + /// The belonging to this . + /// + public Toplevel Toplevel { get; internal set; } + +#if DEBUG_IDISPOSABLE + /// + /// For debug (see DEBUG_IDISPOSABLE define) purposes to verify objects are being disposed properly + /// + public bool WasDisposed = false; + + /// + /// For debug (see DEBUG_IDISPOSABLE define) purposes to verify objects are being disposed properly + /// + public int DisposedCount = 0; + + /// + /// For debug (see DEBUG_IDISPOSABLE define) purposes; the runstate instances that have been created + /// + public static List Instances = new List (); + + /// + /// Creates a new RunState object. + /// + public ApplicationRunState () + { + Instances.Add (this); + } +#endif + + /// + /// Releases all resource used by the object. + /// + /// + /// Call when you are finished using the . + /// + /// + /// method leaves the in an unusable state. After + /// calling , you must release all references to the + /// so the garbage collector can reclaim the memory that the + /// was occupying. + /// + public void Dispose () + { + Dispose (true); + GC.SuppressFinalize (this); +#if DEBUG_IDISPOSABLE + WasDisposed = true; +#endif + } + + /// + /// Releases all resource used by the object. + /// + /// If set to we are disposing and should dispose held objects. + protected virtual void Dispose (bool disposing) + { + if (Toplevel != null && disposing) { + throw new InvalidOperationException ("You must clean up (Dispose) the Toplevel before calling Application.RunState.Dispose"); + } + } + } +} diff --git a/Terminal.Gui/Configuration/ThemeManager.cs b/Terminal.Gui/Configuration/ThemeManager.cs new file mode 100644 index 0000000000..69d1889148 --- /dev/null +++ b/Terminal.Gui/Configuration/ThemeManager.cs @@ -0,0 +1,209 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text.Json.Serialization; + +#nullable enable + +namespace Terminal.Gui { + + /// + /// Contains a dictionary of the s for a Terminal.Gui application. + /// + /// + /// + /// A Theme is a collection of settings that are named. The default theme is named "Default". + /// + /// + /// The property is used to detemrine the currently active theme. + /// + /// + /// + /// is a singleton class. It is created when the first property is accessed. + /// Accessing is the same as accessing . + /// + /// + /// "Themes": [ + /// { + /// "Default": { + /// "ColorSchemes": [ + /// { + /// "TopLevel": { + /// "Normal": { + /// "Foreground": "BrightGreen", + /// "Background": "Black" + /// }, + /// "Focus": { + /// "Foreground": "White", + /// "Background": "Cyan" + /// + /// }, + /// "HotNormal": { + /// "Foreground": "Brown", + /// "Background": "Black" + /// + /// }, + /// "HotFocus": { + /// "Foreground": "Blue", + /// "Background": "Cyan" + /// }, + /// "Disabled": { + /// "Foreground": "DarkGray", + /// "Background": "Black" + /// + /// } + /// } + /// } + /// + public partial class ThemeManager : IDictionary { + private static readonly ThemeManager _instance = new ThemeManager (); + static ThemeManager () { } // Make sure it's truly lazy + private ThemeManager () { } // Prevent instantiation outside + + /// + /// Class is a singleton... + /// + public static ThemeManager Instance { get { return _instance; } } + + private static string _theme = string.Empty; + + /// + /// The currently selected theme. This is the internal version; see . + /// + [JsonInclude, SerializableConfigurationProperty (Scope = typeof (SettingsScope), OmitClassName = true), JsonPropertyName ("Theme")] + internal static string SelectedTheme { + get => _theme; + set { + var oldTheme = _theme; + _theme = value; + if (oldTheme != _theme && + ConfigurationManager.Settings! ["Themes"]?.PropertyValue is Dictionary themes && + themes.ContainsKey (_theme)) { + ConfigurationManager.Settings! ["Theme"].PropertyValue = _theme; + Instance.OnThemeChanged (oldTheme); + } + } + } + + /// + /// Gets or sets the currently selected theme. The value is persisted to the "Theme" + /// property. + /// + [JsonIgnore] + public string Theme { + get => ThemeManager.SelectedTheme; + set { + ThemeManager.SelectedTheme = value; + } + } + + /// + /// Called when the selected theme has changed. Fires the event. + /// + internal void OnThemeChanged (string theme) + { + Debug.WriteLine ($"Themes.OnThemeChanged({theme}) -> {Theme}"); + ThemeChanged?.Invoke (this, new ThemeManagerEventArgs (theme)); + } + + /// + /// Event fired he selected theme has changed. + /// application. + /// + public event EventHandler? ThemeChanged; + + /// + /// Holds the definitions. + /// + [JsonInclude, JsonConverter (typeof (DictionaryJsonConverter))] + [SerializableConfigurationProperty (Scope = typeof (SettingsScope), OmitClassName = true)] + public static Dictionary? Themes { + get => ConfigurationManager.Settings? ["Themes"]?.PropertyValue as Dictionary; // themes ?? new Dictionary (); + set { + //if (themes == null || value == null) { + // themes = value; + //} else { + // themes = (Dictionary)DeepMemberwiseCopy (value!, themes!)!; + //} + ConfigurationManager.Settings! ["Themes"].PropertyValue = value; + } + } + + internal static void Reset () + { + Debug.WriteLine ($"Themes.Reset()"); + + Themes?.Clear (); + SelectedTheme = string.Empty; + } + + internal static void GetHardCodedDefaults () + { + Debug.WriteLine ($"Themes.GetHardCodedDefaults()"); + var theme = new ThemeScope (); + theme.RetrieveValues (); + + Themes = new Dictionary (StringComparer.InvariantCultureIgnoreCase) { { "Default", theme } }; + SelectedTheme = "Default"; + } + + #region IDictionary +#pragma warning disable 1591 + + public ICollection Keys => ((IDictionary)Themes!).Keys; + public ICollection Values => ((IDictionary)Themes!).Values; + public int Count => ((ICollection>)Themes!).Count; + public bool IsReadOnly => ((ICollection>)Themes!).IsReadOnly; + public ThemeScope this [string key] { get => ((IDictionary)Themes!) [key]; set => ((IDictionary)Themes!) [key] = value; } + public void Add (string key, ThemeScope value) + { + ((IDictionary)Themes!).Add (key, value); + } + public bool ContainsKey (string key) + { + return ((IDictionary)Themes!).ContainsKey (key); + } + public bool Remove (string key) + { + return ((IDictionary)Themes!).Remove (key); + } + public bool TryGetValue (string key, out ThemeScope value) + { + return ((IDictionary)Themes!).TryGetValue (key, out value!); + } + public void Add (KeyValuePair item) + { + ((ICollection>)Themes!).Add (item); + } + public void Clear () + { + ((ICollection>)Themes!).Clear (); + } + public bool Contains (KeyValuePair item) + { + return ((ICollection>)Themes!).Contains (item); + } + public void CopyTo (KeyValuePair [] array, int arrayIndex) + { + ((ICollection>)Themes!).CopyTo (array, arrayIndex); + } + public bool Remove (KeyValuePair item) + { + return ((ICollection>)Themes!).Remove (item); + } + public IEnumerator> GetEnumerator () + { + return ((IEnumerable>)Themes!).GetEnumerator (); + } + + IEnumerator IEnumerable.GetEnumerator () + { + return ((IEnumerable)Themes!).GetEnumerator (); + } +#pragma warning restore 1591 + + #endregion + } + +} \ No newline at end of file diff --git a/Terminal.Gui/Configuration/ThemeScope.cs b/Terminal.Gui/Configuration/ThemeScope.cs index 04adf94a52..e9da8fa0ae 100644 --- a/Terminal.Gui/Configuration/ThemeScope.cs +++ b/Terminal.Gui/Configuration/ThemeScope.cs @@ -1,263 +1,56 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Reflection; -using System.Text.Json.Serialization; -using static Terminal.Gui.ConfigurationManager; +using System.Text.Json.Serialization; #nullable enable namespace Terminal.Gui { - public static partial class ConfigurationManager { - /// - /// The root object for a Theme. A Theme is a set of settings that are applied to the running - /// as a group. - /// - /// - /// - /// - /// - /// - /// "Default": { - /// "ColorSchemes": [ - /// { - /// "TopLevel": { - /// "Normal": { - /// "Foreground": "BrightGreen", - /// "Background": "Black" - /// }, - /// "Focus": { - /// "Foreground": "White", - /// "Background": "Cyan" - /// - /// }, - /// "HotNormal": { - /// "Foreground": "Brown", - /// "Background": "Black" - /// - /// }, - /// "HotFocus": { - /// "Foreground": "Blue", - /// "Background": "Cyan" - /// }, - /// "Disabled": { - /// "Foreground": "DarkGray", - /// "Background": "Black" - /// - /// } - /// } - /// - [JsonConverter (typeof (ScopeJsonConverter))] - public class ThemeScope : Scope { - - /// - internal override bool Apply () - { - var ret = base.Apply (); - Application.Driver?.InitalizeColorSchemes (); - return ret; - } - } - - /// - /// Contains a dictionary of the s for a Terminal.Gui application. - /// - /// - /// - /// A Theme is a collection of settings that are named. The default theme is named "Default". - /// - /// - /// The property is used to detemrine the currently active theme. - /// - /// - /// - /// is a singleton class. It is created when the first property is accessed. - /// Accessing is the same as accessing . - /// - /// - /// "Themes": [ - /// { - /// "Default": { - /// "ColorSchemes": [ - /// { - /// "TopLevel": { - /// "Normal": { - /// "Foreground": "BrightGreen", - /// "Background": "Black" - /// }, - /// "Focus": { - /// "Foreground": "White", - /// "Background": "Cyan" - /// - /// }, - /// "HotNormal": { - /// "Foreground": "Brown", - /// "Background": "Black" - /// - /// }, - /// "HotFocus": { - /// "Foreground": "Blue", - /// "Background": "Cyan" - /// }, - /// "Disabled": { - /// "Foreground": "DarkGray", - /// "Background": "Black" - /// - /// } - /// } - /// } - /// - public partial class ThemeManager : IDictionary { - private static readonly ThemeManager _instance = new ThemeManager (); - static ThemeManager () { } // Make sure it's truly lazy - private ThemeManager () { } // Prevent instantiation outside - - /// - /// Class is a singleton... - /// - public static ThemeManager Instance { get { return _instance; } } - - private static string _theme = string.Empty; - - /// - /// The currently selected theme. This is the internal version; see . - /// - [JsonInclude, SerializableConfigurationProperty (Scope = typeof (SettingsScope), OmitClassName = true), JsonPropertyName ("Theme")] - internal static string SelectedTheme { - get => _theme; - set { - var oldTheme = _theme; - _theme = value; - if (oldTheme != _theme && - ConfigurationManager.Settings! ["Themes"]?.PropertyValue is Dictionary themes && - themes.ContainsKey (_theme)) { - ConfigurationManager.Settings! ["Theme"].PropertyValue = _theme; - Instance.OnThemeChanged (oldTheme); - } - } - } - - /// - /// Gets or sets the currently selected theme. The value is persisted to the "Theme" - /// property. - /// - [JsonIgnore] - public string Theme { - get => ThemeManager.SelectedTheme; - set { - ThemeManager.SelectedTheme = value; - } - } - - /// - /// Called when the selected theme has changed. Fires the event. - /// - internal void OnThemeChanged (string theme) - { - Debug.WriteLine ($"Themes.OnThemeChanged({theme}) -> {Theme}"); - ThemeChanged?.Invoke (this, new ThemeManagerEventArgs (theme)); - } - - /// - /// Event fired he selected theme has changed. - /// application. - /// - public event EventHandler? ThemeChanged; - - /// - /// Holds the definitions. - /// - [JsonInclude, JsonConverter (typeof (DictionaryJsonConverter))] - [SerializableConfigurationProperty (Scope = typeof (SettingsScope), OmitClassName = true)] - public static Dictionary? Themes { - get => Settings? ["Themes"]?.PropertyValue as Dictionary; // themes ?? new Dictionary (); - set { - //if (themes == null || value == null) { - // themes = value; - //} else { - // themes = (Dictionary)DeepMemberwiseCopy (value!, themes!)!; - //} - Settings! ["Themes"].PropertyValue = value; - } - } - - internal static void Reset () - { - Debug.WriteLine ($"Themes.Reset()"); - - Themes?.Clear (); - SelectedTheme = string.Empty; - } - - internal static void GetHardCodedDefaults () - { - Debug.WriteLine ($"Themes.GetHardCodedDefaults()"); - var theme = new ThemeScope (); - theme.RetrieveValues (); - - Themes = new Dictionary (StringComparer.InvariantCultureIgnoreCase) { { "Default", theme } }; - SelectedTheme = "Default"; - } - - #region IDictionary -#pragma warning disable 1591 - - public ICollection Keys => ((IDictionary)Themes!).Keys; - public ICollection Values => ((IDictionary)Themes!).Values; - public int Count => ((ICollection>)Themes!).Count; - public bool IsReadOnly => ((ICollection>)Themes!).IsReadOnly; - public ThemeScope this [string key] { get => ((IDictionary)Themes!) [key]; set => ((IDictionary)Themes!) [key] = value; } - public void Add (string key, ThemeScope value) - { - ((IDictionary)Themes!).Add (key, value); - } - public bool ContainsKey (string key) - { - return ((IDictionary)Themes!).ContainsKey (key); - } - public bool Remove (string key) - { - return ((IDictionary)Themes!).Remove (key); - } - public bool TryGetValue (string key, out ThemeScope value) - { - return ((IDictionary)Themes!).TryGetValue (key, out value!); - } - public void Add (KeyValuePair item) - { - ((ICollection>)Themes!).Add (item); - } - public void Clear () - { - ((ICollection>)Themes!).Clear (); - } - public bool Contains (KeyValuePair item) - { - return ((ICollection>)Themes!).Contains (item); - } - public void CopyTo (KeyValuePair [] array, int arrayIndex) - { - ((ICollection>)Themes!).CopyTo (array, arrayIndex); - } - public bool Remove (KeyValuePair item) - { - return ((ICollection>)Themes!).Remove (item); - } - public IEnumerator> GetEnumerator () - { - return ((IEnumerable>)Themes!).GetEnumerator (); - } - - IEnumerator IEnumerable.GetEnumerator () - { - return ((IEnumerable)Themes!).GetEnumerator (); - } -#pragma warning restore 1591 - - #endregion + /// + /// The root object for a Theme. A Theme is a set of settings that are applied to the running + /// as a group. + /// + /// + /// + /// + /// + /// + /// "Default": { + /// "ColorSchemes": [ + /// { + /// "TopLevel": { + /// "Normal": { + /// "Foreground": "BrightGreen", + /// "Background": "Black" + /// }, + /// "Focus": { + /// "Foreground": "White", + /// "Background": "Cyan" + /// + /// }, + /// "HotNormal": { + /// "Foreground": "Brown", + /// "Background": "Black" + /// + /// }, + /// "HotFocus": { + /// "Foreground": "Blue", + /// "Background": "Cyan" + /// }, + /// "Disabled": { + /// "Foreground": "DarkGray", + /// "Background": "Black" + /// + /// } + /// } + /// + [JsonConverter (typeof (ScopeJsonConverter))] + public class ThemeScope : Scope { + + /// + internal override bool Apply () + { + var ret = base.Apply (); + Application.Driver?.InitalizeColorSchemes (); + return ret; } } } \ No newline at end of file diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesMouseEvent.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesMouseEvent.cs new file mode 100644 index 0000000000..a65db0cb12 --- /dev/null +++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesMouseEvent.cs @@ -0,0 +1,67 @@ +// +// TODO: +// * FindNCurses needs to remove the old probing code +// * Removal of that proxy code +// * Need to implement reading pointers with the new API +// * Can remove the manual Dlopen features +// * initscr() diagnostics based on DLL can be fixed +// +// binding.cs.in: Core binding for curses. +// +// This file attempts to call into ncurses without relying on Mono's +// dllmap, so it will work with .NET Core. This means that it needs +// two sets of bindings, one for "ncurses" which works on OSX, and one +// that works against "libncursesw.so.5" which is what you find on +// assorted Linux systems. +// +// Additionally, I do not want to rely on an external native library +// which is why all this pain to bind two separate ncurses is here. +// +// Authors: +// Miguel de Icaza (miguel.de.icaza@gmail.com) +// +// Copyright (C) 2007 Novell (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +using System.Runtime.InteropServices; + +namespace Unix.Terminal { +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + + //[StructLayout (LayoutKind.Sequential)] + //public struct winsize { + // public ushort ws_row; + // public ushort ws_col; + // public ushort ws_xpixel; /* unused */ + // public ushort ws_ypixel; /* unused */ + //}; + + [StructLayout (LayoutKind.Sequential)] + public struct CursesMouseEvent { + public short ID; + public int X, Y, Z; + public Curses.Event ButtonState; + } + +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member +#pragma warning restore CS8981 // The type name only contains lower-cased ascii characters. Such names may become reserved for the language. + +} diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/binding.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/binding.cs index 6d84f62701..eee72a5dce 100644 --- a/Terminal.Gui/ConsoleDrivers/CursesDriver/binding.cs +++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/binding.cs @@ -48,20 +48,6 @@ namespace Unix.Terminal { #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member public partial class Curses { - //[StructLayout (LayoutKind.Sequential)] - //public struct winsize { - // public ushort ws_row; - // public ushort ws_col; - // public ushort ws_xpixel; /* unused */ - // public ushort ws_ypixel; /* unused */ - //}; - - [StructLayout (LayoutKind.Sequential)] - public struct MouseEvent { - public short ID; - public int X, Y, Z; - public Event ButtonState; - } static int lines, cols; static CursesWindow main_window; @@ -310,8 +296,8 @@ static public int IsAlt (int key) static public int init_pair (short pair, short f, short b) => methods.init_pair (pair, f, b); static public int use_default_colors () => methods.use_default_colors (); static public int COLOR_PAIRS () => methods.COLOR_PAIRS (); - static public uint getmouse (out MouseEvent ev) => methods.getmouse (out ev); - static public uint ungetmouse (ref MouseEvent ev) => methods.ungetmouse (ref ev); + static public uint getmouse (out CursesMouseEvent ev) => methods.getmouse (out ev); + static public uint ungetmouse (ref CursesMouseEvent ev) => methods.ungetmouse (ref ev); static public int mouseinterval (int interval) => methods.mouseinterval (interval); static public bool is_term_resized (int lines, int columns) => methods.is_term_resized (lines, columns); static public int resize_term (int lines, int columns) => methods.resize_term (lines, columns); @@ -386,8 +372,8 @@ internal class Delegates { public delegate int init_pair (short pair, short f, short b); public delegate int use_default_colors (); public delegate int COLOR_PAIRS (); - public delegate uint getmouse (out Curses.MouseEvent ev); - public delegate uint ungetmouse (ref Curses.MouseEvent ev); + public delegate uint getmouse (out CursesMouseEvent ev); + public delegate uint ungetmouse (ref CursesMouseEvent ev); public delegate int mouseinterval (int interval); public delegate IntPtr mousemask (IntPtr newmask, out IntPtr oldMask); public delegate bool is_term_resized (int lines, int columns); diff --git a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeClipboard.cs b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeClipboard.cs new file mode 100644 index 0000000000..b5cb8da826 --- /dev/null +++ b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeClipboard.cs @@ -0,0 +1,46 @@ +// +// FakeDriver.cs: A fake ConsoleDriver for unit tests. +// +using System; + +// Alias Console to MockConsole so we don't accidentally use Console + +namespace Terminal.Gui { + + public class FakeClipboard : ClipboardBase { + public Exception FakeException = null; + + string contents = string.Empty; + + bool isSupportedAlwaysFalse = false; + + public override bool IsSupported => !isSupportedAlwaysFalse; + + public FakeClipboard (bool fakeClipboardThrowsNotSupportedException = false, bool isSupportedAlwaysFalse = false) + { + this.isSupportedAlwaysFalse = isSupportedAlwaysFalse; + if (fakeClipboardThrowsNotSupportedException) { + FakeException = new NotSupportedException ("Fake clipboard exception"); + } + } + + protected override string GetClipboardDataImpl () + { + if (FakeException != null) { + throw FakeException; + } + return contents; + } + + protected override void SetClipboardDataImpl (string text) + { + if (FakeException != null) { + throw FakeException; + } + contents = text; + } + } + +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member + +} \ No newline at end of file diff --git a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs index 509cefe874..13c3aaa9fb 100644 --- a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs @@ -670,41 +670,7 @@ public override void UncookMouse () { } - #endregion - - public class FakeClipboard : ClipboardBase { - public Exception FakeException = null; - - string contents = string.Empty; - - bool isSupportedAlwaysFalse = false; - - public override bool IsSupported => !isSupportedAlwaysFalse; - - public FakeClipboard (bool fakeClipboardThrowsNotSupportedException = false, bool isSupportedAlwaysFalse = false) - { - this.isSupportedAlwaysFalse = isSupportedAlwaysFalse; - if (fakeClipboardThrowsNotSupportedException) { - FakeException = new NotSupportedException ("Fake clipboard exception"); - } - } - - protected override string GetClipboardDataImpl () - { - if (FakeException != null) { - throw FakeException; - } - return contents; - } - - protected override void SetClipboardDataImpl (string text) - { - if (FakeException != null) { - throw FakeException; - } - contents = text; - } - } +#endregion #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member } diff --git a/Terminal.Gui/Drawing/LineCanvas.cs b/Terminal.Gui/Drawing/LineCanvas.cs index d0bb56e727..0dd4d3cb31 100644 --- a/Terminal.Gui/Drawing/LineCanvas.cs +++ b/Terminal.Gui/Drawing/LineCanvas.cs @@ -213,9 +213,9 @@ public Dictionary GetMap (Rect inArea) /// so that all lines connect up with the appropriate intersection symbols. /// /// A map of all the points within the canvas. - public Dictionary GetCellMap () + public Dictionary GetCellMap () { - var map = new Dictionary (); + var map = new Dictionary (); // walk through each pixel of the bitmap for (int y = Bounds.Y; y < Bounds.Y + Bounds.Height; y++) { @@ -528,29 +528,13 @@ public override void SetGlyphs () } - /// - /// Represents a single row/column within the . Includes the glyph and the foreground/background colors. - /// - public class Cell { - /// - /// The glyph to draw. - /// - public Rune? Rune { get; set; } - - /// - /// The foreground color to draw the glyph with. - /// - public Attribute? Attribute { get; set; } - - } - - private Cell GetCellForIntersects (ConsoleDriver driver, IntersectionDefinition [] intersects) + private LineCanvasCell GetCellForIntersects (ConsoleDriver driver, IntersectionDefinition [] intersects) { if (!intersects.Any ()) { return null; } - var cell = new Cell (); + var cell = new LineCanvasCell (); cell.Rune = GetRuneForIntersects (driver, intersects); cell.Attribute = GetAttributeForIntersects (intersects); return cell; diff --git a/Terminal.Gui/Drawing/LineCanvasCell.cs b/Terminal.Gui/Drawing/LineCanvasCell.cs new file mode 100644 index 0000000000..ff3ab77e74 --- /dev/null +++ b/Terminal.Gui/Drawing/LineCanvasCell.cs @@ -0,0 +1,21 @@ +using System.Text; + + +namespace Terminal.Gui { + + /// + /// Represents a single row/column within the . Includes the glyph and the foreground/background colors. + /// + public class LineCanvasCell { + /// + /// The glyph to draw. + /// + public Rune? Rune { get; set; } + + /// + /// The foreground color to draw the glyph with. + /// + public Attribute? Attribute { get; set; } + + } +} diff --git a/Terminal.Gui/FileServices/FileDialogStyle.cs b/Terminal.Gui/FileServices/FileDialogStyle.cs index 9b109a1ab4..d0a0fdcdd4 100644 --- a/Terminal.Gui/FileServices/FileDialogStyle.cs +++ b/Terminal.Gui/FileServices/FileDialogStyle.cs @@ -142,7 +142,7 @@ public class FileDialogStyle { /// /// Gets the style settings for the table of files (in currently selected directory). /// - public TableView.TableStyle TableStyle { get; internal set; } + public TableStyle TableStyle { get; internal set; } /// /// Gets the style settings for the collapse-able directory/places tree diff --git a/Terminal.Gui/GlobalSuppressions.cs b/Terminal.Gui/GlobalSuppressions.cs deleted file mode 100644 index 116da79d39..0000000000 --- a/Terminal.Gui/GlobalSuppressions.cs +++ /dev/null @@ -1,8 +0,0 @@ -// This file is used by Code Analysis to maintain SuppressMessage -// attributes that are applied to this project. -// Project-level suppressions either have no target or are given -// a specific target and scoped to a namespace, type, member, etc. - -using System.Diagnostics.CodeAnalysis; - -[assembly: SuppressMessage ("Design", "CA1034:Nested types should not be visible", Justification = "", Scope = "type", Target = "~T:Terminal.Gui.SpinnerStyle.Custom")] diff --git a/Terminal.Gui/MainLoop.cs b/Terminal.Gui/MainLoop.cs index 58775c5c16..05179fbfbb 100644 --- a/Terminal.Gui/MainLoop.cs +++ b/Terminal.Gui/MainLoop.cs @@ -45,7 +45,7 @@ public interface IMainLoopDriver { /// Monitoring of file descriptors is only available on Unix, there /// does not seem to be a way of supporting this on Windows. /// - public partial class MainLoop { + public class MainLoop { internal SortedList timeouts = new SortedList (); object _timeoutsLockToken = new object (); diff --git a/Terminal.Gui/RunStateEventArgs.cs b/Terminal.Gui/RunStateEventArgs.cs index 9b77f7c91d..14c7eea938 100644 --- a/Terminal.Gui/RunStateEventArgs.cs +++ b/Terminal.Gui/RunStateEventArgs.cs @@ -3,7 +3,7 @@ namespace Terminal.Gui { /// - /// Event arguments for events about + /// Event arguments for events about /// public class RunStateEventArgs : EventArgs { @@ -11,7 +11,7 @@ public class RunStateEventArgs : EventArgs { /// Creates a new instance of the class /// /// - public RunStateEventArgs (RunState state) + public RunStateEventArgs (ApplicationRunState state) { State = state; } @@ -19,6 +19,6 @@ public RunStateEventArgs (RunState state) /// /// The state being reported on by the event /// - public RunState State { get; } + public ApplicationRunState State { get; } } } diff --git a/Terminal.Gui/Terminal.Gui.csproj b/Terminal.Gui/Terminal.Gui.csproj index 0cd7977bc6..8934f57dbb 100644 --- a/Terminal.Gui/Terminal.Gui.csproj +++ b/Terminal.Gui/Terminal.Gui.csproj @@ -5,7 +5,7 @@ TRACE;DEBUG_IDISPOSABLE portable - 4 + CA1034 diff --git a/Terminal.Gui/Views/GraphView/Annotations.cs b/Terminal.Gui/Views/GraphView/Annotations.cs index a1857210e2..1ef30c9f68 100644 --- a/Terminal.Gui/Views/GraphView/Annotations.cs +++ b/Terminal.Gui/Views/GraphView/Annotations.cs @@ -213,7 +213,7 @@ public void AddEntry (GraphCellToRender graphCellToRender, string text) /// /// Sequence of lines to connect points e.g. of a /// - public partial class PathAnnotation : IAnnotation { + public class PathAnnotation : IAnnotation { /// /// Points that should be connected. Lines will be drawn between points in the order diff --git a/Terminal.Gui/Views/GraphView/Series.cs b/Terminal.Gui/Views/GraphView/Series.cs index 537fc3fe30..d276a8c305 100644 --- a/Terminal.Gui/Views/GraphView/Series.cs +++ b/Terminal.Gui/Views/GraphView/Series.cs @@ -142,7 +142,7 @@ public void DrawSeries (GraphView graph, Rect drawBounds, RectangleF graphBounds /// /// Series of bars positioned at regular intervals /// - public partial class BarSeries : ISeries { + public class BarSeries : ISeries { /// /// Ordered collection of graph bars to position along axis diff --git a/Terminal.Gui/Views/SpinnerView/SpinnerStyle.cs b/Terminal.Gui/Views/SpinnerView/SpinnerStyle.cs index e8a7fc64aa..56c54f2cae 100644 --- a/Terminal.Gui/Views/SpinnerView/SpinnerStyle.cs +++ b/Terminal.Gui/Views/SpinnerView/SpinnerStyle.cs @@ -27,6 +27,8 @@ using System; +#pragma warning disable CA1034 // Nested types should not be visible + namespace Terminal.Gui { /// /// SpinnerStyles used in a . @@ -1696,4 +1698,6 @@ public class Aesthetic2 : SpinnerStyle { } #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member } -} \ No newline at end of file +} + +#pragma warning restore CA1034 // Nested types should not be visible \ No newline at end of file diff --git a/Terminal.Gui/Views/Tab.cs b/Terminal.Gui/Views/Tab.cs new file mode 100644 index 0000000000..de9a3da8fc --- /dev/null +++ b/Terminal.Gui/Views/Tab.cs @@ -0,0 +1,40 @@ +namespace Terminal.Gui { + + /// + /// A single tab in a + /// + public class Tab { + private string text; + + /// + /// The text to display in a + /// + /// + public string Text { get => text ?? "Unamed"; set => text = value; } + + /// + /// The control to display when the tab is selected + /// + /// + public View View { get; set; } + + /// + /// Creates a new unamed tab with no controls inside + /// + public Tab () + { + + } + + /// + /// Creates a new tab with the given text hosting a view + /// + /// + /// + public Tab (string text, View view) + { + this.Text = text; + this.View = view; + } + } +} diff --git a/Terminal.Gui/Views/TabChangedEventArgs.cs b/Terminal.Gui/Views/TabChangedEventArgs.cs index 5d890a1bc4..e9ed0478f9 100644 --- a/Terminal.Gui/Views/TabChangedEventArgs.cs +++ b/Terminal.Gui/Views/TabChangedEventArgs.cs @@ -10,19 +10,19 @@ public class TabChangedEventArgs : EventArgs { /// /// The previously selected tab. May be null /// - public TabView.Tab OldTab { get; } + public Tab OldTab { get; } /// /// The currently selected tab. May be null /// - public TabView.Tab NewTab { get; } + public Tab NewTab { get; } /// /// Documents a tab change /// /// /// - public TabChangedEventArgs (TabView.Tab oldTab, TabView.Tab newTab) + public TabChangedEventArgs (Tab oldTab, Tab newTab) { OldTab = oldTab; NewTab = newTab; diff --git a/Terminal.Gui/Views/TabMouseEventArgs.cs b/Terminal.Gui/Views/TabMouseEventArgs.cs index fb2e888ded..622477255c 100644 --- a/Terminal.Gui/Views/TabMouseEventArgs.cs +++ b/Terminal.Gui/Views/TabMouseEventArgs.cs @@ -13,7 +13,7 @@ public class TabMouseEventArgs : EventArgs { /// /// This will be null if the click is after last tab /// or before first. - public TabView.Tab Tab { get; } + public Tab Tab { get; } /// /// Gets the actual mouse event. Use to cancel this event @@ -26,7 +26,7 @@ public class TabMouseEventArgs : EventArgs { /// /// that the mouse was over when the event occurred. /// The mouse activity being reported - public TabMouseEventArgs (TabView.Tab tab, MouseEvent mouseEvent) + public TabMouseEventArgs (Tab tab, MouseEvent mouseEvent) { Tab = tab; MouseEvent = mouseEvent; diff --git a/Terminal.Gui/Views/TabStyle.cs b/Terminal.Gui/Views/TabStyle.cs new file mode 100644 index 0000000000..b1c75960e8 --- /dev/null +++ b/Terminal.Gui/Views/TabStyle.cs @@ -0,0 +1,29 @@ +namespace Terminal.Gui { + + /// + /// Describes render stylistic selections of a + /// + public class TabStyle { + + /// + /// True to show the top lip of tabs. False to directly begin with tab text during + /// rendering. When true header line occupies 3 rows, when false only 2. + /// Defaults to true. + /// + /// When is enabled this instead applies to the + /// bottommost line of the control + /// + public bool ShowTopLine { get; set; } = true; + + /// + /// True to show a solid box around the edge of the control. Defaults to true. + /// + public bool ShowBorder { get; set; } = true; + + /// + /// True to render tabs at the bottom of the view instead of the top + /// + public bool TabsOnBottom { get; set; } = false; + + } +} diff --git a/Terminal.Gui/Views/TabView.cs b/Terminal.Gui/Views/TabView.cs index 0f827428d3..84e2b34bc8 100644 --- a/Terminal.Gui/Views/TabView.cs +++ b/Terminal.Gui/Views/TabView.cs @@ -9,7 +9,7 @@ namespace Terminal.Gui { /// /// Control that hosts multiple sub views, presenting a single one at once /// - public partial class TabView : View { + public class TabView : View { private Tab selectedTab; /// @@ -425,8 +425,6 @@ public void RemoveTab (Tab tab) SetNeedsDisplay (); } - #region Nested Types - private class TabToRender { public int X { get; set; } public Tab Tab { get; set; } @@ -745,71 +743,5 @@ protected virtual private void OnTabClicked (TabMouseEventArgs tabMouseEventArgs { TabClicked?.Invoke (this, tabMouseEventArgs); } - - /// - /// A single tab in a - /// - public class Tab { - private string text; - - /// - /// The text to display in a - /// - /// - public string Text { get => text ?? "Unamed"; set => text = value; } - - /// - /// The control to display when the tab is selected - /// - /// - public View View { get; set; } - - /// - /// Creates a new unamed tab with no controls inside - /// - public Tab () - { - - } - - /// - /// Creates a new tab with the given text hosting a view - /// - /// - /// - public Tab (string text, View view) - { - this.Text = text; - this.View = view; - } - } - - /// - /// Describes render stylistic selections of a - /// - public class TabStyle { - - /// - /// True to show the top lip of tabs. False to directly begin with tab text during - /// rendering. When true header line occupies 3 rows, when false only 2. - /// Defaults to true. - /// - /// When is enabled this instead applies to the - /// bottommost line of the control - /// - public bool ShowTopLine { get; set; } = true; - - /// - /// True to show a solid box around the edge of the control. Defaults to true. - /// - public bool ShowBorder { get; set; } = true; - - /// - /// True to render tabs at the bottom of the view instead of the top - /// - public bool TabsOnBottom { get; set; } = false; - - } - #endregion } } diff --git a/Terminal.Gui/Views/TableView/ListTableSource.cs b/Terminal.Gui/Views/TableView/ListTableSource.cs index ef75bd25fd..26a819068b 100644 --- a/Terminal.Gui/Views/TableView/ListTableSource.cs +++ b/Terminal.Gui/Views/TableView/ListTableSource.cs @@ -9,7 +9,7 @@ namespace Terminal.Gui { /// a . This class is /// mutable: changes are permitted to the wrapped . /// - public partial class ListTableSource : ITableSource { + public class ListTableSource : ITableSource { /// /// The list this source wraps. /// diff --git a/Terminal.Gui/Views/TableView/TableStyle.cs b/Terminal.Gui/Views/TableView/TableStyle.cs index bb216bf9f8..98cf313007 100644 --- a/Terminal.Gui/Views/TableView/TableStyle.cs +++ b/Terminal.Gui/Views/TableView/TableStyle.cs @@ -2,134 +2,132 @@ namespace Terminal.Gui { - public partial class TableView { - /// - /// Defines rendering options that affect how the table is displayed. - /// - /// See TableView Deep Dive for more information. - /// - public class TableStyle { - - /// - /// Gets or sets a flag indicating whether to render headers of a . - /// Defaults to . - /// - /// , etc - /// may still be used even if is . - public bool ShowHeaders { get; set; } = true; - - /// - /// When scrolling down always lock the column headers in place as the first row of the table - /// - public bool AlwaysShowHeaders { get; set; } = false; - - /// - /// True to render a solid line above the headers - /// - public bool ShowHorizontalHeaderOverline { get; set; } = true; - - /// - /// True to render a solid line under the headers - /// - public bool ShowHorizontalHeaderUnderline { get; set; } = true; - - /// - /// True to render a solid line vertical line between cells - /// - public bool ShowVerticalCellLines { get; set; } = true; - - /// - /// True to render a solid line vertical line between headers - /// - public bool ShowVerticalHeaderLines { get; set; } = true; - - /// - /// True to render a arrows on the right/left of the table when - /// there are more column(s) that can be scrolled to. Requires - /// to be true. - /// Defaults to true - /// - public bool ShowHorizontalScrollIndicators { get; set; } = true; - - - /// - /// Gets or sets a flag indicating whether there should be a horizontal line after all the data - /// in the table. Defaults to . - /// - public bool ShowHorizontalBottomline { get; set; } = false; - - /// - /// True to invert the colors of the first symbol of the selected cell in the . - /// This gives the appearance of a cursor for when the doesn't otherwise show - /// this - /// - public bool InvertSelectedCellFirstCharacter { get; set; } = false; - - /// - /// Gets or sets a flag indicating whether to force use when rendering - /// vertical cell lines (even when is on). - /// - public bool AlwaysUseNormalColorForVerticalCellLines { get; set; } = false; - - /// - /// Collection of columns for which you want special rendering (e.g. custom column lengths, text alignment etc) - /// - public Dictionary ColumnStyles { get; set; } = new Dictionary (); - - /// - /// Delegate for coloring specific rows in a different color. For cell color - /// - /// - public RowColorGetterDelegate RowColorGetter { get; set; } - - /// - /// Determines rendering when the last column in the table is visible but it's - /// content or is less than the remaining - /// space in the control. True (the default) will expand the column to fill - /// the remaining bounds of the control. False will draw a column ending line - /// and leave a blank column that cannot be selected in the remaining space. - /// - /// - public bool ExpandLastColumn { get; set; } = true; - - /// - /// - /// Determines how is updated when scrolling - /// right off the end of the currently visible area. - /// - /// - /// If true then when scrolling right the scroll offset is increased the minimum required to show - /// the new column. This may be slow if you have an incredibly large number of columns in - /// your table and/or slow implementations - /// - /// - /// If false then scroll offset is set to the currently selected column (i.e. PageRight). - /// - /// - public bool SmoothHorizontalScrolling { get; set; } = true; - - /// - /// Returns the entry from for the given or null if no custom styling is defined for it - /// - /// - /// - public ColumnStyle GetColumnStyleIfAny (int col) - { - return ColumnStyles.TryGetValue (col, out ColumnStyle result) ? result : null; - } - - /// - /// Returns an existing for the given or creates a new one with default options - /// - /// - /// - public ColumnStyle GetOrCreateColumnStyle (int col) - { - if (!ColumnStyles.ContainsKey (col)) - ColumnStyles.Add (col, new ColumnStyle ()); - - return ColumnStyles [col]; - } + /// + /// Defines rendering options that affect how the table is displayed. + /// + /// See TableView Deep Dive for more information. + /// + public class TableStyle { + + /// + /// Gets or sets a flag indicating whether to render headers of a . + /// Defaults to . + /// + /// , etc + /// may still be used even if is . + public bool ShowHeaders { get; set; } = true; + + /// + /// When scrolling down always lock the column headers in place as the first row of the table + /// + public bool AlwaysShowHeaders { get; set; } = false; + + /// + /// True to render a solid line above the headers + /// + public bool ShowHorizontalHeaderOverline { get; set; } = true; + + /// + /// True to render a solid line under the headers + /// + public bool ShowHorizontalHeaderUnderline { get; set; } = true; + + /// + /// True to render a solid line vertical line between cells + /// + public bool ShowVerticalCellLines { get; set; } = true; + + /// + /// True to render a solid line vertical line between headers + /// + public bool ShowVerticalHeaderLines { get; set; } = true; + + /// + /// True to render a arrows on the right/left of the table when + /// there are more column(s) that can be scrolled to. Requires + /// to be true. + /// Defaults to true + /// + public bool ShowHorizontalScrollIndicators { get; set; } = true; + + + /// + /// Gets or sets a flag indicating whether there should be a horizontal line after all the data + /// in the table. Defaults to . + /// + public bool ShowHorizontalBottomline { get; set; } = false; + + /// + /// True to invert the colors of the first symbol of the selected cell in the . + /// This gives the appearance of a cursor for when the doesn't otherwise show + /// this + /// + public bool InvertSelectedCellFirstCharacter { get; set; } = false; + + /// + /// Gets or sets a flag indicating whether to force use when rendering + /// vertical cell lines (even when is on). + /// + public bool AlwaysUseNormalColorForVerticalCellLines { get; set; } = false; + + /// + /// Collection of columns for which you want special rendering (e.g. custom column lengths, text alignment etc) + /// + public Dictionary ColumnStyles { get; set; } = new Dictionary (); + + /// + /// Delegate for coloring specific rows in a different color. For cell color + /// + /// + public RowColorGetterDelegate RowColorGetter { get; set; } + + /// + /// Determines rendering when the last column in the table is visible but it's + /// content or is less than the remaining + /// space in the control. True (the default) will expand the column to fill + /// the remaining bounds of the control. False will draw a column ending line + /// and leave a blank column that cannot be selected in the remaining space. + /// + /// + public bool ExpandLastColumn { get; set; } = true; + + /// + /// + /// Determines how is updated when scrolling + /// right off the end of the currently visible area. + /// + /// + /// If true then when scrolling right the scroll offset is increased the minimum required to show + /// the new column. This may be slow if you have an incredibly large number of columns in + /// your table and/or slow implementations + /// + /// + /// If false then scroll offset is set to the currently selected column (i.e. PageRight). + /// + /// + public bool SmoothHorizontalScrolling { get; set; } = true; + + /// + /// Returns the entry from for the given or null if no custom styling is defined for it + /// + /// + /// + public ColumnStyle GetColumnStyleIfAny (int col) + { + return ColumnStyles.TryGetValue (col, out ColumnStyle result) ? result : null; + } + + /// + /// Returns an existing for the given or creates a new one with default options + /// + /// + /// + public ColumnStyle GetOrCreateColumnStyle (int col) + { + if (!ColumnStyles.ContainsKey (col)) + ColumnStyles.Add (col, new ColumnStyle ()); + + return ColumnStyles [col]; } } } \ No newline at end of file diff --git a/Terminal.Gui/Views/TableView/TableView.cs b/Terminal.Gui/Views/TableView/TableView.cs index 760d5759ee..c26f4b7e6e 100644 --- a/Terminal.Gui/Views/TableView/TableView.cs +++ b/Terminal.Gui/Views/TableView/TableView.cs @@ -26,7 +26,7 @@ namespace Terminal.Gui { /// /// See TableView Deep Dive for more information. /// - public partial class TableView : View { + public class TableView : View { private int columnOffset; private int rowOffset; diff --git a/Terminal.Gui/Views/TileView.cs b/Terminal.Gui/Views/TileView.cs index 7a04cd2f91..ca199587a9 100644 --- a/Terminal.Gui/Views/TileView.cs +++ b/Terminal.Gui/Views/TileView.cs @@ -9,7 +9,7 @@ namespace Terminal.Gui { /// A consisting of a moveable bar that divides /// the display area into resizeable . /// - public partial class TileView : View { + public class TileView : View { TileView parentTileView; /// diff --git a/Terminal.Gui/Views/Toplevel.cs b/Terminal.Gui/Views/Toplevel.cs index fc9113fa22..2d43aba76e 100644 --- a/Terminal.Gui/Views/Toplevel.cs +++ b/Terminal.Gui/Views/Toplevel.cs @@ -31,9 +31,9 @@ public partial class Toplevel : View { public bool Running { get; set; } /// - /// Invoked when the has begun to be loaded. + /// Invoked when the has begun to be loaded. /// A Loaded event handler is a good place to finalize initialization before calling - /// . + /// . /// public event EventHandler Loaded; @@ -47,51 +47,51 @@ public partial class Toplevel : View { public event EventHandler Ready; /// - /// Invoked when the Toplevel has been unloaded. - /// A Unloaded event handler is a good place to dispose objects after calling . + /// Invoked when the Toplevel has been unloaded. + /// A Unloaded event handler is a good place to dispose objects after calling . /// public event EventHandler Unloaded; /// - /// Invoked when the Toplevel becomes the Toplevel. + /// Invoked when the Toplevel becomes the Toplevel. /// public event EventHandler Activate; /// - /// Invoked when the Toplevel ceases to be the Toplevel. + /// Invoked when the Toplevel ceases to be the Toplevel. /// public event EventHandler Deactivate; /// - /// Invoked when a child of the Toplevel is closed by - /// . + /// Invoked when a child of the Toplevel is closed by + /// . /// public event EventHandler ChildClosed; /// - /// Invoked when the last child of the Toplevel is closed from - /// by . + /// Invoked when the last child of the Toplevel is closed from + /// by . /// public event EventHandler AllChildClosed; /// - /// Invoked when the Toplevel's is being closed by + /// Invoked when the Toplevel's is being closed by /// . /// public event EventHandler Closing; /// - /// Invoked when the Toplevel's is closed by . + /// Invoked when the Toplevel's is closed by . /// public event EventHandler Closed; /// - /// Invoked when a child Toplevel's has been loaded. + /// Invoked when a child Toplevel's has been loaded. /// public event EventHandler ChildLoaded; /// - /// Invoked when a cjhild Toplevel's has been unloaded. + /// Invoked when a cjhild Toplevel's has been unloaded. /// public event EventHandler ChildUnloaded; @@ -174,7 +174,7 @@ internal virtual void OnReady () } /// - /// Called from before the is disposed. + /// Called from before the is disposed. /// internal virtual void OnUnloaded () { diff --git a/Terminal.Gui/Views/Wizard/Wizard.cs b/Terminal.Gui/Views/Wizard/Wizard.cs index 138a404c72..8b8d0c89bd 100644 --- a/Terminal.Gui/Views/Wizard/Wizard.cs +++ b/Terminal.Gui/Views/Wizard/Wizard.cs @@ -54,7 +54,7 @@ namespace Terminal.Gui { /// Application.Shutdown (); /// /// - public partial class Wizard : Dialog { + public class Wizard : Dialog { /// /// Initializes a new instance of the class using positioning. diff --git a/UICatalog/Scenarios/Editor.cs b/UICatalog/Scenarios/Editor.cs index 0a12818939..9c2edcc080 100644 --- a/UICatalog/Scenarios/Editor.cs +++ b/UICatalog/Scenarios/Editor.cs @@ -751,9 +751,9 @@ private void CreateFindReplace (bool isFind = true) Height = Dim.Fill () }; - _tabView.AddTab (new TabView.Tab ("Find", FindTab ()), isFind); + _tabView.AddTab (new Tab ("Find", FindTab ()), isFind); var replace = ReplaceTab (); - _tabView.AddTab (new TabView.Tab ("Replace", replace), !isFind); + _tabView.AddTab (new Tab ("Replace", replace), !isFind); _tabView.SelectedTabChanged += (s, e) => _tabView.SelectedTab.View.FocusFirst (); _winDialog.Add (_tabView); diff --git a/UICatalog/Scenarios/Notepad.cs b/UICatalog/Scenarios/Notepad.cs index 17f6245c46..372c1c7336 100644 --- a/UICatalog/Scenarios/Notepad.cs +++ b/UICatalog/Scenarios/Notepad.cs @@ -186,7 +186,7 @@ private void Close () { Close (focusedTabView, focusedTabView.SelectedTab); } - private void Close (TabView tv, TabView.Tab tabToClose) + private void Close (TabView tv, Tab tabToClose) { var tab = tabToClose as OpenedFile; @@ -285,7 +285,7 @@ public void Save () { Save (focusedTabView, focusedTabView.SelectedTab); } - public void Save (TabView tabViewToSave, TabView.Tab tabToSave) + public void Save (TabView tabViewToSave, Tab tabToSave) { var tab = tabToSave as OpenedFile; @@ -327,7 +327,7 @@ public bool SaveAs () return true; } - private class OpenedFile : TabView.Tab { + private class OpenedFile : Tab { public FileInfo File { get; set; } /// diff --git a/UICatalog/Scenarios/TabViewExample.cs b/UICatalog/Scenarios/TabViewExample.cs index 875fa59c1d..b0c74b019a 100644 --- a/UICatalog/Scenarios/TabViewExample.cs +++ b/UICatalog/Scenarios/TabViewExample.cs @@ -59,18 +59,18 @@ public override void Setup () Height = 20, }; - tabView.AddTab (new TabView.Tab ("Tab1", new Label ("hodor!")), false); - tabView.AddTab (new TabView.Tab ("Tab2", new Label ("durdur")), false); - tabView.AddTab (new TabView.Tab ("Interactive Tab", GetInteractiveTab ()), false); - tabView.AddTab (new TabView.Tab ("Big Text", GetBigTextFileTab ()), false); - tabView.AddTab (new TabView.Tab ( + tabView.AddTab (new Tab ("Tab1", new Label ("hodor!")), false); + tabView.AddTab (new Tab ("Tab2", new Label ("durdur")), false); + tabView.AddTab (new Tab ("Interactive Tab", GetInteractiveTab ()), false); + tabView.AddTab (new Tab ("Big Text", GetBigTextFileTab ()), false); + tabView.AddTab (new Tab ( "Long name Tab, I mean seriously long. Like you would not believe how long this tab's name is its just too much really woooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooowwww thats long", new Label ("This tab has a very long name which should be truncated. See TabView.MaxTabTextWidth")), false); - tabView.AddTab (new TabView.Tab ("Les Mise" + Char.ConvertFromUtf32 (Int32.Parse ("0301", NumberStyles.HexNumber)) + "rables", new Label ("This tab name is unicode")), false); + tabView.AddTab (new Tab ("Les Mise" + Char.ConvertFromUtf32 (Int32.Parse ("0301", NumberStyles.HexNumber)) + "rables", new Label ("This tab name is unicode")), false); for (int i = 0; i < 100; i++) { - tabView.AddTab (new TabView.Tab ($"Tab{i}", new Label ($"Welcome to tab {i}")), false); + tabView.AddTab (new Tab ($"Tab{i}", new Label ($"Welcome to tab {i}")), false); } tabView.SelectedTab = tabView.Tabs.First (); @@ -115,7 +115,7 @@ public override void Setup () private void AddBlankTab () { - tabView.AddTab (new TabView.Tab (), false); + tabView.AddTab (new Tab (), false); } private View GetInteractiveTab () diff --git a/UICatalog/UICatalog.cs b/UICatalog/UICatalog.cs index 13f3b7b094..aacd74b355 100644 --- a/UICatalog/UICatalog.cs +++ b/UICatalog/UICatalog.cs @@ -839,10 +839,10 @@ static void VerifyObjectsWereDisposed () // Validate there are no outstanding Application.RunState-based instances // after a scenario was selected to run. This proves the main UI Catalog // 'app' closed cleanly. - foreach (var inst in Application.RunState.Instances) { + foreach (var inst in ApplicationRunState.Instances) { Debug.Assert (inst.WasDisposed); } - Application.RunState.Instances.Clear (); + ApplicationRunState.Instances.Clear (); #endif } diff --git a/UnitTests/Application/ApplicationTests.cs b/UnitTests/Application/ApplicationTests.cs index 07dbbc4aa3..1d2fe75792 100644 --- a/UnitTests/Application/ApplicationTests.cs +++ b/UnitTests/Application/ApplicationTests.cs @@ -15,7 +15,7 @@ public ApplicationTests () { #if DEBUG_IDISPOSABLE Responder.Instances.Clear (); - Application.RunState.Instances.Clear (); + ApplicationRunState.Instances.Clear (); #endif } @@ -142,7 +142,7 @@ public void Init_Begin_End_Cleans_Up () Application.RequestStop (); }; - Application.RunState runstate = null; + ApplicationRunState runstate = null; EventHandler NewRunStateFn = (s, e) => { Assert.NotNull (e.State); runstate = e.State; @@ -187,7 +187,7 @@ public void InitWithTopLevelFactory_Begin_End_Cleans_Up () Toplevel topLevel = null; Application.InternalInit (() => topLevel = new TestToplevel (), new FakeDriver ()); - Application.RunState runstate = null; + ApplicationRunState runstate = null; EventHandler NewRunStateFn = (s, e) => { Assert.NotNull (e.State); runstate = e.State; diff --git a/UnitTests/Application/RunStateTests.cs b/UnitTests/Application/RunStateTests.cs index ffae6abba5..72c02217d6 100644 --- a/UnitTests/Application/RunStateTests.cs +++ b/UnitTests/Application/RunStateTests.cs @@ -18,25 +18,25 @@ public RunStateTests () { #if DEBUG_IDISPOSABLE Responder.Instances.Clear (); - Application.RunState.Instances.Clear (); + ApplicationRunState.Instances.Clear (); #endif } [Fact] public void New_Creates_RunState () { - var rs = new Application.RunState (null); + var rs = new ApplicationRunState (null); Assert.Null (rs.Toplevel); var top = new Toplevel (); - rs = new Application.RunState (top); + rs = new ApplicationRunState (top); Assert.Equal (top, rs.Toplevel); } [Fact] public void Dispose_Cleans_Up_RunState () { - var rs = new Application.RunState (null); + var rs = new ApplicationRunState (null); Assert.NotNull (rs); // Should not throw because Toplevel was null @@ -45,7 +45,7 @@ public void Dispose_Cleans_Up_RunState () Assert.True (rs.WasDisposed); #endif var top = new Toplevel (); - rs = new Application.RunState (top); + rs = new ApplicationRunState (top); Assert.NotNull (rs); // Should throw because Toplevel was not cleaned up @@ -73,7 +73,7 @@ void Shutdown () Application.Shutdown (); #if DEBUG_IDISPOSABLE // Validate there are no outstanding RunState-based instances left - foreach (var inst in Application.RunState.Instances) Assert.True (inst.WasDisposed); + foreach (var inst in ApplicationRunState.Instances) Assert.True (inst.WasDisposed); #endif } diff --git a/UnitTests/Configuration/AppScopeTests.cs b/UnitTests/Configuration/AppScopeTests.cs index 743de08b18..d95da106b3 100644 --- a/UnitTests/Configuration/AppScopeTests.cs +++ b/UnitTests/Configuration/AppScopeTests.cs @@ -63,7 +63,7 @@ public void Apply_ShouldApplyUpdatedProperties () Assert.True (AppSettingsTestClass.TestProperty); // ConfigurationManager.Themes should NOT apply theme settings - ConfigurationManager.ThemeManager.Themes! [ThemeManager.SelectedTheme]!.Apply (); + ThemeManager.Themes! [ThemeManager.SelectedTheme]!.Apply (); Assert.True (AppSettingsTestClass.TestProperty); // ConfigurationManager.AppSettings should NOT apply theme settings diff --git a/UnitTests/Configuration/SettingsScopeTests.cs b/UnitTests/Configuration/SettingsScopeTests.cs index 2bf36b167a..4e1fc28f18 100644 --- a/UnitTests/Configuration/SettingsScopeTests.cs +++ b/UnitTests/Configuration/SettingsScopeTests.cs @@ -15,7 +15,7 @@ public void GetHardCodedDefaults_ShouldSetProperties () { ConfigurationManager.Reset (); - Assert.Equal (3, ((Dictionary)ConfigurationManager.Settings ["Themes"].PropertyValue).Count); + Assert.Equal (3, ((Dictionary)ConfigurationManager.Settings ["Themes"].PropertyValue).Count); ConfigurationManager.GetHardCodedDefaults (); Assert.NotEmpty (ConfigurationManager.Themes); @@ -30,8 +30,8 @@ public void GetHardCodedDefaults_ShouldSetProperties () Assert.True (ConfigurationManager.Settings ["Theme"].PropertyValue is string); Assert.Equal ("Default", ConfigurationManager.Settings ["Theme"].PropertyValue as string); - Assert.True (ConfigurationManager.Settings ["Themes"].PropertyValue is Dictionary); - Assert.Single (((Dictionary)ConfigurationManager.Settings ["Themes"].PropertyValue)); + Assert.True (ConfigurationManager.Settings ["Themes"].PropertyValue is Dictionary); + Assert.Single (((Dictionary)ConfigurationManager.Settings ["Themes"].PropertyValue)); } diff --git a/UnitTests/Configuration/ThemeScopeTests.cs b/UnitTests/Configuration/ThemeScopeTests.cs index 206b715d77..99a0d8ffbe 100644 --- a/UnitTests/Configuration/ThemeScopeTests.cs +++ b/UnitTests/Configuration/ThemeScopeTests.cs @@ -21,15 +21,15 @@ public class ThemeScopeTests { public void ThemeManager_ClassMethodsWork () { ConfigurationManager.Reset (); - Assert.Equal (ConfigurationManager.ThemeManager.Instance, ConfigurationManager.Themes); - Assert.NotEmpty (ConfigurationManager.ThemeManager.Themes); + Assert.Equal (ThemeManager.Instance, ConfigurationManager.Themes); + Assert.NotEmpty (ThemeManager.Themes); - ConfigurationManager.ThemeManager.SelectedTheme = "foo"; - Assert.Equal ("foo", ConfigurationManager.ThemeManager.SelectedTheme); - ConfigurationManager.ThemeManager.Reset (); - Assert.Equal (string.Empty, ConfigurationManager.ThemeManager.SelectedTheme); + ThemeManager.SelectedTheme = "foo"; + Assert.Equal ("foo", ThemeManager.SelectedTheme); + ThemeManager.Reset (); + Assert.Equal (string.Empty, ThemeManager.SelectedTheme); - Assert.Empty (ConfigurationManager.ThemeManager.Themes); + Assert.Empty (ThemeManager.Themes); } [Fact] @@ -59,7 +59,7 @@ public void Apply_ShouldApplyUpdatedProperties () ConfigurationManager.Themes ["Default"] ["Dialog.DefaultButtonAlignment"].PropertyValue = Dialog.ButtonAlignments.Right; - ConfigurationManager.ThemeManager.Themes! [ThemeManager.SelectedTheme]!.Apply (); + ThemeManager.Themes! [ThemeManager.SelectedTheme]!.Apply (); Assert.Equal (Dialog.ButtonAlignments.Right, Dialog.DefaultButtonAlignment); } @@ -69,7 +69,7 @@ public void TestSerialize_RoundTrip () { ConfigurationManager.Reset (); - var initial = ConfigurationManager.ThemeManager.Themes; + var initial = ThemeManager.Themes; var serialized = JsonSerializer.Serialize> (ConfigurationManager.Themes, _jsonOptions); var deserialized = JsonSerializer.Deserialize> (serialized, _jsonOptions); diff --git a/UnitTests/Dialogs/DialogTests.cs b/UnitTests/Dialogs/DialogTests.cs index d73ff36c47..642d0edbe8 100644 --- a/UnitTests/Dialogs/DialogTests.cs +++ b/UnitTests/Dialogs/DialogTests.cs @@ -42,7 +42,7 @@ public DialogTests (ITestOutputHelper output) // Application.End (runstate); //} - private (Application.RunState, Dialog) RunButtonTestDialog (string title, int width, Dialog.ButtonAlignments align, params Button [] btns) + private (ApplicationRunState, Dialog) RunButtonTestDialog (string title, int width, Dialog.ButtonAlignments align, params Button [] btns) { var dlg = new Dialog (btns) { Title = title, @@ -209,7 +209,7 @@ public void Location_When_Not_Application_Top_Not_Default () public void ButtonAlignment_One () { var d = (FakeDriver)Application.Driver; - Application.RunState runstate = null; + ApplicationRunState runstate = null; var title = "1234"; // E.g "|[ ok ]|" @@ -281,7 +281,7 @@ public void ButtonAlignment_One () [AutoInitShutdown] public void ButtonAlignment_Two () { - Application.RunState runstate = null; + ApplicationRunState runstate = null; var d = (FakeDriver)Application.Driver; @@ -327,7 +327,7 @@ public void ButtonAlignment_Two () [AutoInitShutdown] public void ButtonAlignment_Two_Hidden () { - Application.RunState runstate = null; + ApplicationRunState runstate = null; bool firstIteration = false; var d = (FakeDriver)Application.Driver; @@ -394,7 +394,7 @@ public void ButtonAlignment_Two_Hidden () [AutoInitShutdown] public void ButtonAlignment_Three () { - Application.RunState runstate = null; + ApplicationRunState runstate = null; var d = (FakeDriver)Application.Driver; @@ -442,7 +442,7 @@ public void ButtonAlignment_Three () [AutoInitShutdown] public void ButtonAlignment_Four () { - Application.RunState runstate = null; + ApplicationRunState runstate = null; var d = (FakeDriver)Application.Driver; @@ -493,7 +493,7 @@ public void ButtonAlignment_Four () [AutoInitShutdown] public void ButtonAlignment_Four_On_Too_Small_Width () { - Application.RunState runstate = null; + ApplicationRunState runstate = null; var d = (FakeDriver)Application.Driver; @@ -540,7 +540,7 @@ public void ButtonAlignment_Four_On_Too_Small_Width () [AutoInitShutdown] public void ButtonAlignment_Four_Wider () { - Application.RunState runstate = null; + ApplicationRunState runstate = null; var d = (FakeDriver)Application.Driver; @@ -594,7 +594,7 @@ public void ButtonAlignment_Four_Wider () [AutoInitShutdown] public void ButtonAlignment_Four_WideOdd () { - Application.RunState runstate = null; + ApplicationRunState runstate = null; var d = (FakeDriver)Application.Driver; @@ -647,7 +647,7 @@ public void ButtonAlignment_Four_WideOdd () [AutoInitShutdown] public void Zero_Buttons_Works () { - Application.RunState runstate = null; + ApplicationRunState runstate = null; var d = (FakeDriver)Application.Driver; @@ -667,7 +667,7 @@ public void Zero_Buttons_Works () [AutoInitShutdown] public void One_Button_Works () { - Application.RunState runstate = null; + ApplicationRunState runstate = null; var d = (FakeDriver)Application.Driver; @@ -687,7 +687,7 @@ public void One_Button_Works () [AutoInitShutdown] public void Add_Button_Works () { - Application.RunState runstate = null; + ApplicationRunState runstate = null; var d = (FakeDriver)Application.Driver; diff --git a/UnitTests/View/Layout/PosTests.cs b/UnitTests/View/Layout/PosTests.cs index b7642e0c12..1f7ea4d6b0 100644 --- a/UnitTests/View/Layout/PosTests.cs +++ b/UnitTests/View/Layout/PosTests.cs @@ -547,9 +547,9 @@ public void LeftTopBottomRight_Win_ShouldNotThrow () return (win, button); } - Application.RunState rs; + ApplicationRunState rs; - void cleanup (Application.RunState rs) + void cleanup (ApplicationRunState rs) { // Cleanup Application.End (rs); diff --git a/UnitTests/Views/ButtonTests.cs b/UnitTests/Views/ButtonTests.cs index 61c831671b..5097ade02e 100644 --- a/UnitTests/Views/ButtonTests.cs +++ b/UnitTests/Views/ButtonTests.cs @@ -474,7 +474,7 @@ public void AutoSize_False_With_Fixed_Width () Width = Dim.Fill (), Height = Dim.Fill () }; - tabView.AddTab (new TabView.Tab ("Find", tab), true); + tabView.AddTab (new Tab ("Find", tab), true); var win = new Window () { Width = Dim.Fill (), diff --git a/UnitTests/Views/OverlappedTests.cs b/UnitTests/Views/OverlappedTests.cs index cc1afcc3ad..bfc902ab29 100644 --- a/UnitTests/Views/OverlappedTests.cs +++ b/UnitTests/Views/OverlappedTests.cs @@ -15,7 +15,7 @@ public OverlappedTests () { #if DEBUG_IDISPOSABLE Responder.Instances.Clear (); - Application.RunState.Instances.Clear (); + ApplicationRunState.Instances.Clear (); #endif } diff --git a/UnitTests/Views/TabViewTests.cs b/UnitTests/Views/TabViewTests.cs index 339f18a59b..38c021609e 100644 --- a/UnitTests/Views/TabViewTests.cs +++ b/UnitTests/Views/TabViewTests.cs @@ -23,15 +23,15 @@ private TabView GetTabView () return GetTabView (out _, out _); } - private TabView GetTabView (out TabView.Tab tab1, out TabView.Tab tab2, bool initFakeDriver = true) + private TabView GetTabView (out Tab tab1, out Tab tab2, bool initFakeDriver = true) { if (initFakeDriver) InitFakeDriver (); var tv = new TabView (); tv.ColorScheme = new ColorScheme (); - tv.AddTab (tab1 = new TabView.Tab ("Tab1", new TextField ("hi")), false); - tv.AddTab (tab2 = new TabView.Tab ("Tab2", new Label ("hi2")), false); + tv.AddTab (tab1 = new Tab ("Tab1", new TextField ("hi")), false); + tv.AddTab (tab2 = new Tab ("Tab2", new Label ("hi2")), false); return tv; } @@ -41,10 +41,10 @@ public void AddTwoTabs_SecondIsSelected () InitFakeDriver (); var tv = new TabView (); - TabView.Tab tab1; - TabView.Tab tab2; - tv.AddTab (tab1 = new TabView.Tab ("Tab1", new TextField ("hi")), false); - tv.AddTab (tab2 = new TabView.Tab ("Tab1", new Label ("hi2")), true); + Tab tab1; + Tab tab2; + tv.AddTab (tab1 = new Tab ("Tab1", new TextField ("hi")), false); + tv.AddTab (tab2 = new Tab ("Tab1", new Label ("hi2")), true); Assert.Equal (2, tv.Tabs.Count); Assert.Equal (tab2, tv.SelectedTab); @@ -98,8 +98,8 @@ public void SelectedTabChanged_Called () tv.SelectedTab = tab1; - TabView.Tab oldTab = null; - TabView.Tab newTab = null; + Tab oldTab = null; + Tab newTab = null; int called = 0; tv.SelectedTabChanged += (s, e) => { @@ -172,13 +172,13 @@ public void SwitchTabBy_NormalUsage () { var tv = GetTabView (out var tab1, out var tab2); - TabView.Tab tab3; - TabView.Tab tab4; - TabView.Tab tab5; + Tab tab3; + Tab tab4; + Tab tab5; - tv.AddTab (tab3 = new TabView.Tab (), false); - tv.AddTab (tab4 = new TabView.Tab (), false); - tv.AddTab (tab5 = new TabView.Tab (), false); + tv.AddTab (tab3 = new Tab (), false); + tv.AddTab (tab4 = new Tab (), false); + tv.AddTab (tab5 = new Tab (), false); tv.SelectedTab = tab1; @@ -320,7 +320,7 @@ public void ShowTopLine_False_TabsOnBottom_False_TestThinTabView_WithLongNames ( var tv = GetTabView (out var tab1, out var tab2, false); tv.Width = 10; tv.Height = 5; - tv.Style = new TabView.TabStyle { ShowTopLine = false }; + tv.Style = new TabStyle { ShowTopLine = false }; tv.ApplyStyleChanges (); // Ensures that the tab bar subview gets the bounds of the parent TabView @@ -414,7 +414,7 @@ public void ShowTopLine_False_TabsOnBottom_False_TestTabView_Width4 () var tv = GetTabView (out _, out _, false); tv.Width = 4; tv.Height = 5; - tv.Style = new TabView.TabStyle { ShowTopLine = false }; + tv.Style = new TabStyle { ShowTopLine = false }; tv.ApplyStyleChanges (); tv.LayoutSubviews (); @@ -452,7 +452,7 @@ public void ShowTopLine_False_TabsOnBottom_False_TestTabView_Width3 () var tv = GetTabView (out _, out _, false); tv.Width = 3; tv.Height = 5; - tv.Style = new TabView.TabStyle { ShowTopLine = false }; + tv.Style = new TabStyle { ShowTopLine = false }; tv.ApplyStyleChanges (); tv.LayoutSubviews (); @@ -472,7 +472,7 @@ public void ShowTopLine_True_TabsOnBottom_True_TestThinTabView_WithLongNames () var tv = GetTabView (out var tab1, out var tab2, false); tv.Width = 10; tv.Height = 5; - tv.Style = new TabView.TabStyle { TabsOnBottom = true }; + tv.Style = new TabStyle { TabsOnBottom = true }; tv.ApplyStyleChanges (); // Ensures that the tab bar subview gets the bounds of the parent TabView @@ -535,7 +535,7 @@ public void ShowTopLine_False_TabsOnBottom_True_TestThinTabView_WithLongNames () var tv = GetTabView (out var tab1, out var tab2, false); tv.Width = 10; tv.Height = 5; - tv.Style = new TabView.TabStyle { ShowTopLine = false, TabsOnBottom = true }; + tv.Style = new TabStyle { ShowTopLine = false, TabsOnBottom = true }; tv.ApplyStyleChanges (); // Ensures that the tab bar subview gets the bounds of the parent TabView @@ -611,7 +611,7 @@ public void ShowTopLine_True_TabsOnBottom_True_TestTabView_Width4 () var tv = GetTabView (out _, out _, false); tv.Width = 4; tv.Height = 5; - tv.Style = new TabView.TabStyle { TabsOnBottom = true }; + tv.Style = new TabStyle { TabsOnBottom = true }; tv.ApplyStyleChanges (); tv.LayoutSubviews (); @@ -631,7 +631,7 @@ public void ShowTopLine_False_TabsOnBottom_True_TestTabView_Width4 () var tv = GetTabView (out _, out _, false); tv.Width = 4; tv.Height = 5; - tv.Style = new TabView.TabStyle { ShowTopLine = false, TabsOnBottom = true }; + tv.Style = new TabStyle { ShowTopLine = false, TabsOnBottom = true }; tv.ApplyStyleChanges (); tv.LayoutSubviews (); @@ -651,7 +651,7 @@ public void ShowTopLine_True_TabsOnBottom_True_TestTabView_Width3 () var tv = GetTabView (out _, out _, false); tv.Width = 3; tv.Height = 5; - tv.Style = new TabView.TabStyle { TabsOnBottom = true }; + tv.Style = new TabStyle { TabsOnBottom = true }; tv.ApplyStyleChanges (); tv.LayoutSubviews (); @@ -671,7 +671,7 @@ public void ShowTopLine_False_TabsOnBottom_True_TestTabView_Width3 () var tv = GetTabView (out _, out _, false); tv.Width = 3; tv.Height = 5; - tv.Style = new TabView.TabStyle { ShowTopLine = false, TabsOnBottom = true }; + tv.Style = new TabStyle { ShowTopLine = false, TabsOnBottom = true }; tv.ApplyStyleChanges (); tv.LayoutSubviews (); @@ -724,7 +724,7 @@ public void ShowTopLine_True_TabsOnBottom_True_With_Unicode () var tv = GetTabView (out var tab1, out var tab2, false); tv.Width = 20; tv.Height = 5; - tv.Style = new TabView.TabStyle { TabsOnBottom = true }; + tv.Style = new TabStyle { TabsOnBottom = true }; tv.ApplyStyleChanges (); tv.LayoutSubviews (); @@ -776,7 +776,7 @@ public void MouseClick_ChangesTab () └──────────────────┘ ", output); - TabView.Tab clicked = null; + Tab clicked = null; tv.TabClicked += (s,e)=>{ From 57776b8c8e6f39d828db8fc062a925527a576fe1 Mon Sep 17 00:00:00 2001 From: tznind Date: Mon, 22 May 2023 20:25:56 +0100 Subject: [PATCH 4/9] Remove partial keyword from ThemeManager as it is no longer needed --- Terminal.Gui/Configuration/ThemeManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Terminal.Gui/Configuration/ThemeManager.cs b/Terminal.Gui/Configuration/ThemeManager.cs index 69d1889148..1886e65576 100644 --- a/Terminal.Gui/Configuration/ThemeManager.cs +++ b/Terminal.Gui/Configuration/ThemeManager.cs @@ -56,7 +56,7 @@ namespace Terminal.Gui { /// } /// } /// - public partial class ThemeManager : IDictionary { + public class ThemeManager : IDictionary { private static readonly ThemeManager _instance = new ThemeManager (); static ThemeManager () { } // Make sure it's truly lazy private ThemeManager () { } // Prevent instantiation outside From 6386aec7f7a694445bc86245747e7b249bd38e4a Mon Sep 17 00:00:00 2001 From: tznind Date: Mon, 22 May 2023 20:27:57 +0100 Subject: [PATCH 5/9] Rename Bar to BarSeriesBar to more clearly indicate it is part of GraphView subsystem --- .../GraphView/{Bar.cs => BarSeriesBar.cs} | 4 +- Terminal.Gui/Views/GraphView/Series.cs | 10 +- UICatalog/Scenarios/GraphViewExample.cs | 130 +++++++++--------- UnitTests/Views/GraphViewTests.cs | 12 +- 4 files changed, 78 insertions(+), 78 deletions(-) rename Terminal.Gui/Views/GraphView/{Bar.cs => BarSeriesBar.cs} (91%) diff --git a/Terminal.Gui/Views/GraphView/Bar.cs b/Terminal.Gui/Views/GraphView/BarSeriesBar.cs similarity index 91% rename from Terminal.Gui/Views/GraphView/Bar.cs rename to Terminal.Gui/Views/GraphView/BarSeriesBar.cs index c98a86e7c7..3f3df31a25 100644 --- a/Terminal.Gui/Views/GraphView/Bar.cs +++ b/Terminal.Gui/Views/GraphView/BarSeriesBar.cs @@ -3,7 +3,7 @@ /// /// A single bar in a /// - public class Bar { + public class BarSeriesBar { /// /// Optional text that describes the bar. This will be rendered on the corresponding @@ -29,7 +29,7 @@ public class Bar { /// /// /// - public Bar (string text, GraphCellToRender fill, float value) + public BarSeriesBar (string text, GraphCellToRender fill, float value) { Text = text; Fill = fill; diff --git a/Terminal.Gui/Views/GraphView/Series.cs b/Terminal.Gui/Views/GraphView/Series.cs index d276a8c305..b7adbb0717 100644 --- a/Terminal.Gui/Views/GraphView/Series.cs +++ b/Terminal.Gui/Views/GraphView/Series.cs @@ -119,7 +119,7 @@ public void AddBars (string label, Rune fill, params float [] values) } for (int i = 0; i < values.Length; i++) { - subSeries [i].Bars.Add (new Bar (label, + subSeries [i].Bars.Add (new BarSeriesBar (label, new GraphCellToRender (fill), values [i])); } } @@ -147,7 +147,7 @@ public class BarSeries : ISeries { /// /// Ordered collection of graph bars to position along axis /// - public List Bars { get; set; } = new List (); + public List Bars { get; set; } = new List (); /// /// Determines the spacing of bars along the axis. Defaults to 1 i.e. @@ -169,12 +169,12 @@ public class BarSeries : ISeries { public float Offset { get; set; } = 0; /// - /// Overrides the with a fixed color + /// Overrides the with a fixed color /// public Attribute? OverrideBarColor { get; set; } /// - /// True to draw along the axis under the bar. Defaults + /// True to draw along the axis under the bar. Defaults /// to true. /// public bool DrawLabels { get; set; } = true; @@ -268,7 +268,7 @@ public virtual void DrawSeries (GraphView graph, Rect drawBounds, RectangleF gra /// Screen position of the start of the bar /// Screen position of the end of the bar /// The Bar that occupies this space and is being drawn - protected virtual void DrawBarLine (GraphView graph, Point start, Point end, Bar beingDrawn) + protected virtual void DrawBarLine (GraphView graph, Point start, Point end, BarSeriesBar beingDrawn) { var adjusted = AdjustColor (beingDrawn.Fill); diff --git a/UICatalog/Scenarios/GraphViewExample.cs b/UICatalog/Scenarios/GraphViewExample.cs index 703a94af23..b6b495e537 100644 --- a/UICatalog/Scenarios/GraphViewExample.cs +++ b/UICatalog/Scenarios/GraphViewExample.cs @@ -302,24 +302,24 @@ private void SetupLifeExpectancyBarGraph (bool verticalBars) var mediumStiple = new GraphCellToRender ((Rune)'\u2592'); var barSeries = new BarSeries () { - Bars = new List () { - new Bar ("Switzerland", softStiple, 83.4f), - new Bar ("South Korea", !verticalBars?mediumStiple:softStiple, 83.3f), - new Bar ("Singapore", softStiple, 83.2f), - new Bar ("Spain", !verticalBars?mediumStiple:softStiple, 83.2f), - new Bar ("Cyprus", softStiple, 83.1f), - new Bar ("Australia", !verticalBars?mediumStiple:softStiple, 83), - new Bar ("Italy", softStiple, 83), - new Bar ("Norway", !verticalBars?mediumStiple:softStiple, 83), - new Bar ("Israel", softStiple, 82.6f), - new Bar ("France", !verticalBars?mediumStiple:softStiple, 82.5f), - new Bar ("Luxembourg", softStiple, 82.4f), - new Bar ("Sweden", !verticalBars?mediumStiple:softStiple, 82.4f), - new Bar ("Iceland", softStiple, 82.3f), - new Bar ("Canada", !verticalBars?mediumStiple:softStiple, 82.2f), - new Bar ("New Zealand", softStiple, 82), - new Bar ("Malta", !verticalBars?mediumStiple:softStiple, 81.9f), - new Bar ("Ireland", softStiple, 81.8f) + Bars = new List () { + new BarSeriesBar ("Switzerland", softStiple, 83.4f), + new BarSeriesBar ("South Korea", !verticalBars?mediumStiple:softStiple, 83.3f), + new BarSeriesBar ("Singapore", softStiple, 83.2f), + new BarSeriesBar ("Spain", !verticalBars?mediumStiple:softStiple, 83.2f), + new BarSeriesBar ("Cyprus", softStiple, 83.1f), + new BarSeriesBar ("Australia", !verticalBars?mediumStiple:softStiple, 83), + new BarSeriesBar ("Italy", softStiple, 83), + new BarSeriesBar ("Norway", !verticalBars?mediumStiple:softStiple, 83), + new BarSeriesBar ("Israel", softStiple, 82.6f), + new BarSeriesBar ("France", !verticalBars?mediumStiple:softStiple, 82.5f), + new BarSeriesBar ("Luxembourg", softStiple, 82.4f), + new BarSeriesBar ("Sweden", !verticalBars?mediumStiple:softStiple, 82.4f), + new BarSeriesBar ("Iceland", softStiple, 82.3f), + new BarSeriesBar ("Canada", !verticalBars?mediumStiple:softStiple, 82.2f), + new BarSeriesBar ("New Zealand", softStiple, 82), + new BarSeriesBar ("Malta", !verticalBars?mediumStiple:softStiple, 81.9f), + new BarSeriesBar ("Ireland", softStiple, 81.8f) } }; @@ -436,29 +436,29 @@ private void SetupPopulationPyramid () // Males (negative to make the bars go left) var malesSeries = new BarSeries () { Orientation = Orientation.Horizontal, - Bars = new List () + Bars = new List () { - new Bar("0-4",stiple,-2009363), - new Bar("5-9",stiple,-2108550), - new Bar("10-14",stiple,-2022370), - new Bar("15-19",stiple,-1880611), - new Bar("20-24",stiple,-2072674), - new Bar("25-29",stiple,-2275138), - new Bar("30-34",stiple,-2361054), - new Bar("35-39",stiple,-2279836), - new Bar("40-44",stiple,-2148253), - new Bar("45-49",stiple,-2128343), - new Bar("50-54",stiple,-2281421), - new Bar("55-59",stiple,-2232388), - new Bar("60-64",stiple,-1919839), - new Bar("65-69",stiple,-1647391), - new Bar("70-74",stiple,-1624635), - new Bar("75-79",stiple,-1137438), - new Bar("80-84",stiple,-766956), - new Bar("85-89",stiple,-438663), - new Bar("90-94",stiple,-169952), - new Bar("95-99",stiple,-34524), - new Bar("100+",stiple,-3016) + new BarSeriesBar("0-4",stiple,-2009363), + new BarSeriesBar("5-9",stiple,-2108550), + new BarSeriesBar("10-14",stiple,-2022370), + new BarSeriesBar("15-19",stiple,-1880611), + new BarSeriesBar("20-24",stiple,-2072674), + new BarSeriesBar("25-29",stiple,-2275138), + new BarSeriesBar("30-34",stiple,-2361054), + new BarSeriesBar("35-39",stiple,-2279836), + new BarSeriesBar("40-44",stiple,-2148253), + new BarSeriesBar("45-49",stiple,-2128343), + new BarSeriesBar("50-54",stiple,-2281421), + new BarSeriesBar("55-59",stiple,-2232388), + new BarSeriesBar("60-64",stiple,-1919839), + new BarSeriesBar("65-69",stiple,-1647391), + new BarSeriesBar("70-74",stiple,-1624635), + new BarSeriesBar("75-79",stiple,-1137438), + new BarSeriesBar("80-84",stiple,-766956), + new BarSeriesBar("85-89",stiple,-438663), + new BarSeriesBar("90-94",stiple,-169952), + new BarSeriesBar("95-99",stiple,-34524), + new BarSeriesBar("100+",stiple,-3016) } }; @@ -467,29 +467,29 @@ private void SetupPopulationPyramid () // Females var femalesSeries = new BarSeries () { Orientation = Orientation.Horizontal, - Bars = new List () + Bars = new List () { - new Bar("0-4",stiple,1915127), - new Bar("5-9",stiple,2011016), - new Bar("10-14",stiple,1933970), - new Bar("15-19",stiple,1805522), - new Bar("20-24",stiple,2001966), - new Bar("25-29",stiple,2208929), - new Bar("30-34",stiple,2345774), - new Bar("35-39",stiple,2308360), - new Bar("40-44",stiple,2159877), - new Bar("45-49",stiple,2167778), - new Bar("50-54",stiple,2353119), - new Bar("55-59",stiple,2306537), - new Bar("60-64",stiple,1985177), - new Bar("65-69",stiple,1734370), - new Bar("70-74",stiple,1763853), - new Bar("75-79",stiple,1304709), - new Bar("80-84",stiple,969611), - new Bar("85-89",stiple,638892), - new Bar("90-94",stiple,320625), - new Bar("95-99",stiple,95559), - new Bar("100+",stiple,12818) + new BarSeriesBar("0-4",stiple,1915127), + new BarSeriesBar("5-9",stiple,2011016), + new BarSeriesBar("10-14",stiple,1933970), + new BarSeriesBar("15-19",stiple,1805522), + new BarSeriesBar("20-24",stiple,2001966), + new BarSeriesBar("25-29",stiple,2208929), + new BarSeriesBar("30-34",stiple,2345774), + new BarSeriesBar("35-39",stiple,2308360), + new BarSeriesBar("40-44",stiple,2159877), + new BarSeriesBar("45-49",stiple,2167778), + new BarSeriesBar("50-54",stiple,2353119), + new BarSeriesBar("55-59",stiple,2306537), + new BarSeriesBar("60-64",stiple,1985177), + new BarSeriesBar("65-69",stiple,1734370), + new BarSeriesBar("70-74",stiple,1763853), + new BarSeriesBar("75-79",stiple,1304709), + new BarSeriesBar("80-84",stiple,969611), + new BarSeriesBar("85-89",stiple,638892), + new BarSeriesBar("90-94",stiple,320625), + new BarSeriesBar("95-99",stiple,95559), + new BarSeriesBar("100+",stiple,12818) } }; @@ -526,7 +526,7 @@ public DiscoBarSeries () red = Application.Driver.MakeAttribute (Color.Red, Color.Black); brightred = Application.Driver.MakeAttribute (Color.BrightRed, Color.Black); } - protected override void DrawBarLine (GraphView graph, Terminal.Gui.Point start, Terminal.Gui.Point end, Bar beingDrawn) + protected override void DrawBarLine (GraphView graph, Terminal.Gui.Point start, Terminal.Gui.Point end, BarSeriesBar beingDrawn) { var driver = Application.Driver; @@ -564,7 +564,7 @@ private void SetupDisco () Random r = new Random (); var series = new DiscoBarSeries (); - var bars = new List (); + var bars = new List (); Func genSample = (l) => { @@ -572,7 +572,7 @@ private void SetupDisco () // generate an imaginary sample for (int i = 0; i < 31; i++) { bars.Add ( - new Bar (null, stiple, r.Next (0, 100)) { + new BarSeriesBar (null, stiple, r.Next (0, 100)) { //ColorGetter = colorDelegate }); } diff --git a/UnitTests/Views/GraphViewTests.cs b/UnitTests/Views/GraphViewTests.cs index 7794d3540b..4086902577 100644 --- a/UnitTests/Views/GraphViewTests.cs +++ b/UnitTests/Views/GraphViewTests.cs @@ -711,7 +711,7 @@ public void TestZeroHeightBar_WithName () Assert.Empty (axisY.LabelPoints); // bar of height 0 - barSeries.Bars.Add (new Bar ("hi", new GraphCellToRender ((Rune)'.'), 0)); + barSeries.Bars.Add (new BarSeriesBar ("hi", new GraphCellToRender ((Rune)'.'), 0)); barSeries.Orientation = Orientation.Vertical; // redraw graph @@ -753,9 +753,9 @@ public void TestTwoTallBars_WithOffset () barSeries.BarEvery = 1f; barSeries.Bars.Add ( - new Bar ("hi1", new GraphCellToRender ((Rune)'.'), 100)); + new BarSeriesBar ("hi1", new GraphCellToRender ((Rune)'.'), 100)); barSeries.Bars.Add ( - new Bar ("hi2", new GraphCellToRender ((Rune)'.'), 100)); + new BarSeriesBar ("hi2", new GraphCellToRender ((Rune)'.'), 100)); barSeries.Orientation = Orientation.Vertical; @@ -809,11 +809,11 @@ public void TestOneLongOneShortHorizontalBars_WithOffset () // 1 bar that is very wide (100 graph units horizontally = screen pos 50 but bounded by screen) barSeries.Bars.Add ( - new Bar ("hi1", new GraphCellToRender ((Rune)'.'), 100)); + new BarSeriesBar ("hi1", new GraphCellToRender ((Rune)'.'), 100)); // 1 bar that is shorter barSeries.Bars.Add ( - new Bar ("hi2", new GraphCellToRender ((Rune)'.'), 5)); + new BarSeriesBar ("hi2", new GraphCellToRender ((Rune)'.'), 5)); // redraw graph graph.Draw (); @@ -860,7 +860,7 @@ protected override GraphCellToRender AdjustColor (GraphCellToRender graphCellToR return FinalColor = base.AdjustColor (graphCellToRender); } - protected override void DrawBarLine (GraphView graph, Point start, Point end, Bar beingDrawn) + protected override void DrawBarLine (GraphView graph, Point start, Point end, BarSeriesBar beingDrawn) { base.DrawBarLine (graph, start, end, beingDrawn); From e7911134d2cf7b0e04358c05247e0d889f027edf Mon Sep 17 00:00:00 2001 From: tznind Date: Mon, 22 May 2023 20:31:23 +0100 Subject: [PATCH 6/9] Fix xmldoc references --- Terminal.Gui/ApplicationRunState.cs | 12 +++++------ .../ConfigurationManagerEventArgs.cs | 2 +- Terminal.Gui/Views/TabMouseEventArgs.cs | 6 +++--- Terminal.Gui/Views/TabView.cs | 2 +- Terminal.Gui/Views/Toplevel.cs | 20 +++++++++---------- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Terminal.Gui/ApplicationRunState.cs b/Terminal.Gui/ApplicationRunState.cs index 400248247d..cd9e188706 100644 --- a/Terminal.Gui/ApplicationRunState.cs +++ b/Terminal.Gui/ApplicationRunState.cs @@ -45,16 +45,16 @@ public ApplicationRunState () #endif /// - /// Releases all resource used by the object. + /// Releases all resource used by the object. /// /// - /// Call when you are finished using the . + /// Call when you are finished using the . /// /// - /// method leaves the in an unusable state. After + /// method leaves the in an unusable state. After /// calling , you must release all references to the - /// so the garbage collector can reclaim the memory that the - /// was occupying. + /// so the garbage collector can reclaim the memory that the + /// was occupying. /// public void Dispose () { @@ -66,7 +66,7 @@ public void Dispose () } /// - /// Releases all resource used by the object. + /// Releases all resource used by the object. /// /// If set to we are disposing and should dispose held objects. protected virtual void Dispose (bool disposing) diff --git a/Terminal.Gui/Configuration/ConfigurationManagerEventArgs.cs b/Terminal.Gui/Configuration/ConfigurationManagerEventArgs.cs index 7e191a7df7..66c12693fa 100644 --- a/Terminal.Gui/Configuration/ConfigurationManagerEventArgs.cs +++ b/Terminal.Gui/Configuration/ConfigurationManagerEventArgs.cs @@ -17,7 +17,7 @@ public ConfigurationManagerEventArgs () } /// - /// Event arguments for the events. + /// Event arguments for the events. /// public class ThemeManagerEventArgs : EventArgs { /// diff --git a/Terminal.Gui/Views/TabMouseEventArgs.cs b/Terminal.Gui/Views/TabMouseEventArgs.cs index 622477255c..7e0acebd3e 100644 --- a/Terminal.Gui/Views/TabMouseEventArgs.cs +++ b/Terminal.Gui/Views/TabMouseEventArgs.cs @@ -3,12 +3,12 @@ namespace Terminal.Gui { /// - /// Describes a mouse event over a specific in a . + /// Describes a mouse event over a specific in a . /// public class TabMouseEventArgs : EventArgs { /// - /// Gets the (if any) that the mouse + /// Gets the (if any) that the mouse /// was over when the occurred. /// /// This will be null if the click is after last tab @@ -24,7 +24,7 @@ public class TabMouseEventArgs : EventArgs { /// /// Creates a new instance of the class. /// - /// that the mouse was over when the event occurred. + /// that the mouse was over when the event occurred. /// The mouse activity being reported public TabMouseEventArgs (Tab tab, MouseEvent mouseEvent) { diff --git a/Terminal.Gui/Views/TabView.cs b/Terminal.Gui/Views/TabView.cs index 84e2b34bc8..b4ae68ab4c 100644 --- a/Terminal.Gui/Views/TabView.cs +++ b/Terminal.Gui/Views/TabView.cs @@ -54,7 +54,7 @@ public class TabView : View { public event EventHandler SelectedTabChanged; /// - /// Event fired when a is clicked. Can be used to cancel navigation, + /// Event fired when a is clicked. Can be used to cancel navigation, /// show context menu (e.g. on right click) etc. /// public event EventHandler TabClicked; diff --git a/Terminal.Gui/Views/Toplevel.cs b/Terminal.Gui/Views/Toplevel.cs index 2d43aba76e..c207614777 100644 --- a/Terminal.Gui/Views/Toplevel.cs +++ b/Terminal.Gui/Views/Toplevel.cs @@ -31,9 +31,9 @@ public partial class Toplevel : View { public bool Running { get; set; } /// - /// Invoked when the has begun to be loaded. + /// Invoked when the has begun to be loaded. /// A Loaded event handler is a good place to finalize initialization before calling - /// . + /// . /// public event EventHandler Loaded; @@ -47,30 +47,30 @@ public partial class Toplevel : View { public event EventHandler Ready; /// - /// Invoked when the Toplevel has been unloaded. - /// A Unloaded event handler is a good place to dispose objects after calling . + /// Invoked when the Toplevel has been unloaded. + /// A Unloaded event handler is a good place to dispose objects after calling . /// public event EventHandler Unloaded; /// - /// Invoked when the Toplevel becomes the Toplevel. + /// Invoked when the Toplevel becomes the Toplevel. /// public event EventHandler Activate; /// - /// Invoked when the Toplevel ceases to be the Toplevel. + /// Invoked when the Toplevel ceases to be the Toplevel. /// public event EventHandler Deactivate; /// - /// Invoked when a child of the Toplevel is closed by - /// . + /// Invoked when a child of the Toplevel is closed by + /// . /// public event EventHandler ChildClosed; /// - /// Invoked when the last child of the Toplevel is closed from - /// by . + /// Invoked when the last child of the Toplevel is closed from + /// by . /// public event EventHandler AllChildClosed; From d405d5bc163369541a218dc79d11a654932cbd2b Mon Sep 17 00:00:00 2001 From: tznind Date: Tue, 23 May 2023 06:28:46 +0100 Subject: [PATCH 7/9] Revert nesting changes to ConsoleDrivers --- .../CursesDriver/CursesDriver.cs | 6 +- .../CursesDriver/CursesMouseEvent.cs | 67 -------- .../CursesDriver/CursesWindow.cs | 162 ------------------ .../ConsoleDrivers/CursesDriver/binding.cs | 28 ++- .../ConsoleDrivers/CursesDriver/handles.cs | 125 ++++++++++++++ .../FakeDriver/FakeClipboard.cs | 46 ----- .../ConsoleDrivers/FakeDriver/FakeConsole.cs | 3 - .../ConsoleDrivers/FakeDriver/FakeDriver.cs | 58 ++++++- .../FakeDriver/FakeDriverBehaviors.cs | 26 --- Terminal.Gui/ConsoleDrivers/NetDriver.cs | 12 +- Terminal.Gui/Terminal.Gui.csproj | 2 +- Terminal.Gui/Views/Toplevel.cs | 10 +- 12 files changed, 219 insertions(+), 326 deletions(-) delete mode 100644 Terminal.Gui/ConsoleDrivers/CursesDriver/CursesMouseEvent.cs delete mode 100644 Terminal.Gui/ConsoleDrivers/CursesDriver/CursesWindow.cs delete mode 100644 Terminal.Gui/ConsoleDrivers/FakeDriver/FakeClipboard.cs delete mode 100644 Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriverBehaviors.cs diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs index 107a1f27b0..eaba76d7e4 100644 --- a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs @@ -180,7 +180,7 @@ public override void SetAttribute (Attribute c) Curses.attrset (CurrentAttribute); } - public CursesWindow window; + public Curses.Window window; //static short last_color_pair = 16; @@ -592,7 +592,7 @@ public override void Init (Action terminalResized) Curses.raw (); Curses.noecho (); - CursesWindow.Standard.keypad (true); + Curses.Window.Standard.keypad (true); TerminalResized = terminalResized; StartReportingMouseMoves (); @@ -765,7 +765,7 @@ public override void Suspend () { StopReportingMouseMoves (); Platform.Suspend (); - CursesWindow.Standard.redrawwin (); + Curses.Window.Standard.redrawwin (); Curses.refresh (); StartReportingMouseMoves (); } diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesMouseEvent.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesMouseEvent.cs deleted file mode 100644 index a65db0cb12..0000000000 --- a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesMouseEvent.cs +++ /dev/null @@ -1,67 +0,0 @@ -// -// TODO: -// * FindNCurses needs to remove the old probing code -// * Removal of that proxy code -// * Need to implement reading pointers with the new API -// * Can remove the manual Dlopen features -// * initscr() diagnostics based on DLL can be fixed -// -// binding.cs.in: Core binding for curses. -// -// This file attempts to call into ncurses without relying on Mono's -// dllmap, so it will work with .NET Core. This means that it needs -// two sets of bindings, one for "ncurses" which works on OSX, and one -// that works against "libncursesw.so.5" which is what you find on -// assorted Linux systems. -// -// Additionally, I do not want to rely on an external native library -// which is why all this pain to bind two separate ncurses is here. -// -// Authors: -// Miguel de Icaza (miguel.de.icaza@gmail.com) -// -// Copyright (C) 2007 Novell (http://www.novell.com) -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -using System.Runtime.InteropServices; - -namespace Unix.Terminal { -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member - - //[StructLayout (LayoutKind.Sequential)] - //public struct winsize { - // public ushort ws_row; - // public ushort ws_col; - // public ushort ws_xpixel; /* unused */ - // public ushort ws_ypixel; /* unused */ - //}; - - [StructLayout (LayoutKind.Sequential)] - public struct CursesMouseEvent { - public short ID; - public int X, Y, Z; - public Curses.Event ButtonState; - } - -#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member -#pragma warning restore CS8981 // The type name only contains lower-cased ascii characters. Such names may become reserved for the language. - -} diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesWindow.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesWindow.cs deleted file mode 100644 index b9975e232a..0000000000 --- a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesWindow.cs +++ /dev/null @@ -1,162 +0,0 @@ -// -// handles.cs: OO wrappers for some curses objects -// -// Authors: -// Miguel de Icaza (miguel.de.icaza@gmail.com) -// -// Copyright (C) 2007 Novell (http://www.novell.com) -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -using System; - -namespace Unix.Terminal { -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member - - public class CursesWindow { - public readonly IntPtr Handle; - static CursesWindow curscr; - static CursesWindow stdscr; - - static CursesWindow () - { - Curses.initscr (); - stdscr = new CursesWindow (Curses.console_sharp_get_stdscr ()); - curscr = new CursesWindow (Curses.console_sharp_get_curscr ()); - } - - internal CursesWindow (IntPtr handle) - { - Handle = handle; - } - - static public CursesWindow Standard { - get { - return stdscr; - } - } - - static public CursesWindow Current { - get { - return curscr; - } - } - - public int wtimeout (int delay) - { - return Curses.wtimeout (Handle, delay); - } - - public int notimeout (bool bf) - { - return Curses.notimeout (Handle, bf); - } - - public int keypad (bool bf) - { - return Curses.keypad (Handle, bf); - } - - public int meta (bool bf) - { - return Curses.meta (Handle, bf); - } - - public int intrflush (bool bf) - { - return Curses.intrflush (Handle, bf); - } - - public int clearok (bool bf) - { - return Curses.clearok (Handle, bf); - } - - public int idlok (bool bf) - { - return Curses.idlok (Handle, bf); - } - - public void idcok (bool bf) - { - Curses.idcok (Handle, bf); - } - - public void immedok (bool bf) - { - Curses.immedok (Handle, bf); - } - - public int leaveok (bool bf) - { - return Curses.leaveok (Handle, bf); - } - - public int setscrreg (int top, int bot) - { - return Curses.wsetscrreg (Handle, top, bot); - } - - public int scrollok (bool bf) - { - return Curses.scrollok (Handle, bf); - } - - public int wrefresh () - { - return Curses.wrefresh (Handle); - } - - public int redrawwin () - { - return Curses.redrawwin (Handle); - } - -#if false - public int wredrawwin (int beg_line, int num_lines) - { - return Curses.wredrawwin (Handle, beg_line, num_lines); - } -#endif - public int wnoutrefresh () - { - return Curses.wnoutrefresh (Handle); - } - - public int move (int line, int col) - { - return Curses.wmove (Handle, line, col); - } - - public int addch (char ch) - { - return Curses.waddch (Handle, ch); - } - - public int refresh () - { - return Curses.wrefresh (Handle); - } - } - -#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member - - -} diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/binding.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/binding.cs index eee72a5dce..8a0ed3da78 100644 --- a/Terminal.Gui/ConsoleDrivers/CursesDriver/binding.cs +++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/binding.cs @@ -48,9 +48,23 @@ namespace Unix.Terminal { #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member public partial class Curses { + //[StructLayout (LayoutKind.Sequential)] + //public struct winsize { + // public ushort ws_row; + // public ushort ws_col; + // public ushort ws_xpixel; /* unused */ + // public ushort ws_ypixel; /* unused */ + //}; + + [StructLayout (LayoutKind.Sequential)] + public struct MouseEvent { + public short ID; + public int X, Y, Z; + public Event ButtonState; + } static int lines, cols; - static CursesWindow main_window; + static Window main_window; static IntPtr curses_handle, curscr_ptr, lines_ptr, cols_ptr; // If true, uses the DllImport into "ncurses", otherwise "libncursesw.so.5" @@ -83,7 +97,7 @@ static void FindNCurses () cols_ptr = get_ptr ("COLS"); } - static public CursesWindow initscr () + static public Window initscr () { setlocale (LC_ALL, ""); FindNCurses (); @@ -91,7 +105,7 @@ static public CursesWindow initscr () // Prevents the terminal from being locked after exiting. reset_shell_mode (); - main_window = new CursesWindow (methods.initscr ()); + main_window = new Window (methods.initscr ()); try { console_sharp_get_dims (out lines, out cols); } catch (DllNotFoundException) { @@ -296,8 +310,8 @@ static public int IsAlt (int key) static public int init_pair (short pair, short f, short b) => methods.init_pair (pair, f, b); static public int use_default_colors () => methods.use_default_colors (); static public int COLOR_PAIRS () => methods.COLOR_PAIRS (); - static public uint getmouse (out CursesMouseEvent ev) => methods.getmouse (out ev); - static public uint ungetmouse (ref CursesMouseEvent ev) => methods.ungetmouse (ref ev); + static public uint getmouse (out MouseEvent ev) => methods.getmouse (out ev); + static public uint ungetmouse (ref MouseEvent ev) => methods.ungetmouse (ref ev); static public int mouseinterval (int interval) => methods.mouseinterval (interval); static public bool is_term_resized (int lines, int columns) => methods.is_term_resized (lines, columns); static public int resize_term (int lines, int columns) => methods.resize_term (lines, columns); @@ -372,8 +386,8 @@ internal class Delegates { public delegate int init_pair (short pair, short f, short b); public delegate int use_default_colors (); public delegate int COLOR_PAIRS (); - public delegate uint getmouse (out CursesMouseEvent ev); - public delegate uint ungetmouse (ref CursesMouseEvent ev); + public delegate uint getmouse (out Curses.MouseEvent ev); + public delegate uint ungetmouse (ref Curses.MouseEvent ev); public delegate int mouseinterval (int interval); public delegate IntPtr mousemask (IntPtr newmask, out IntPtr oldMask); public delegate bool is_term_resized (int lines, int columns); diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/handles.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/handles.cs index ad3510aece..8a46149d50 100644 --- a/Terminal.Gui/ConsoleDrivers/CursesDriver/handles.cs +++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/handles.cs @@ -30,6 +30,131 @@ namespace Unix.Terminal { #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member public partial class Curses { + public class Window { + public readonly IntPtr Handle; + static Window curscr; + static Window stdscr; + + static Window () + { + Curses.initscr (); + stdscr = new Window (Curses.console_sharp_get_stdscr ()); + curscr = new Window (Curses.console_sharp_get_curscr ()); + } + + internal Window (IntPtr handle) + { + Handle = handle; + } + + static public Window Standard { + get { + return stdscr; + } + } + + static public Window Current { + get { + return curscr; + } + } + + public int wtimeout (int delay) + { + return Curses.wtimeout (Handle, delay); + } + + public int notimeout (bool bf) + { + return Curses.notimeout (Handle, bf); + } + + public int keypad (bool bf) + { + return Curses.keypad (Handle, bf); + } + + public int meta (bool bf) + { + return Curses.meta (Handle, bf); + } + + public int intrflush (bool bf) + { + return Curses.intrflush (Handle, bf); + } + + public int clearok (bool bf) + { + return Curses.clearok (Handle, bf); + } + + public int idlok (bool bf) + { + return Curses.idlok (Handle, bf); + } + + public void idcok (bool bf) + { + Curses.idcok (Handle, bf); + } + + public void immedok (bool bf) + { + Curses.immedok (Handle, bf); + } + + public int leaveok (bool bf) + { + return Curses.leaveok (Handle, bf); + } + + public int setscrreg (int top, int bot) + { + return Curses.wsetscrreg (Handle, top, bot); + } + + public int scrollok (bool bf) + { + return Curses.scrollok (Handle, bf); + } + + public int wrefresh () + { + return Curses.wrefresh (Handle); + } + + public int redrawwin () + { + return Curses.redrawwin (Handle); + } + +#if false + public int wredrawwin (int beg_line, int num_lines) + { + return Curses.wredrawwin (Handle, beg_line, num_lines); + } +#endif + public int wnoutrefresh () + { + return Curses.wnoutrefresh (Handle); + } + + public int move (int line, int col) + { + return Curses.wmove (Handle, line, col); + } + + public int addch (char ch) + { + return Curses.waddch (Handle, ch); + } + + public int refresh () + { + return Curses.wrefresh (Handle); + } + } // Currently unused, to do later internal class Screen { diff --git a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeClipboard.cs b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeClipboard.cs deleted file mode 100644 index b5cb8da826..0000000000 --- a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeClipboard.cs +++ /dev/null @@ -1,46 +0,0 @@ -// -// FakeDriver.cs: A fake ConsoleDriver for unit tests. -// -using System; - -// Alias Console to MockConsole so we don't accidentally use Console - -namespace Terminal.Gui { - - public class FakeClipboard : ClipboardBase { - public Exception FakeException = null; - - string contents = string.Empty; - - bool isSupportedAlwaysFalse = false; - - public override bool IsSupported => !isSupportedAlwaysFalse; - - public FakeClipboard (bool fakeClipboardThrowsNotSupportedException = false, bool isSupportedAlwaysFalse = false) - { - this.isSupportedAlwaysFalse = isSupportedAlwaysFalse; - if (fakeClipboardThrowsNotSupportedException) { - FakeException = new NotSupportedException ("Fake clipboard exception"); - } - } - - protected override string GetClipboardDataImpl () - { - if (FakeException != null) { - throw FakeException; - } - return contents; - } - - protected override void SetClipboardDataImpl (string text) - { - if (FakeException != null) { - throw FakeException; - } - contents = text; - } - } - -#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member - -} \ No newline at end of file diff --git a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeConsole.cs b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeConsole.cs index 852130f6cf..75a58f9c32 100644 --- a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeConsole.cs +++ b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeConsole.cs @@ -6,9 +6,6 @@ using System.IO; using System.Text; -// Alias Console to MockConsole so we don't accidentally use Console -using Console = Terminal.Gui.FakeConsole; - namespace Terminal.Gui { #pragma warning disable RCS1138 // Add summary to documentation comment. diff --git a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs index 13c3aaa9fb..2f7df9534d 100644 --- a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs @@ -3,6 +3,7 @@ // using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; using System.Threading; @@ -12,16 +13,31 @@ using Console = Terminal.Gui.FakeConsole; namespace Terminal.Gui { - /// /// Implements a mock ConsoleDriver for unit testing /// public class FakeDriver : ConsoleDriver { #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member - + public class Behaviors { + + public bool UseFakeClipboard { get; internal set; } + public bool FakeClipboardAlwaysThrowsNotSupportedException { get; internal set; } + public bool FakeClipboardIsSupportedAlwaysFalse { get; internal set; } + + public Behaviors (bool useFakeClipboard = false, bool fakeClipboardAlwaysThrowsNotSupportedException = false, bool fakeClipboardIsSupportedAlwaysTrue = false) + { + UseFakeClipboard = useFakeClipboard; + FakeClipboardAlwaysThrowsNotSupportedException = fakeClipboardAlwaysThrowsNotSupportedException; + FakeClipboardIsSupportedAlwaysFalse = fakeClipboardIsSupportedAlwaysTrue; + + // double check usage is correct + Debug.Assert (useFakeClipboard == false && fakeClipboardAlwaysThrowsNotSupportedException == false); + Debug.Assert (useFakeClipboard == false && fakeClipboardIsSupportedAlwaysTrue == false); + } + } - public static FakeDriverBehaviors FakeBehaviors = new FakeDriverBehaviors (); + public static FakeDriver.Behaviors FakeBehaviors = new Behaviors (); int cols, rows, left, top; public override int Cols => cols; @@ -670,7 +686,41 @@ public override void UncookMouse () { } -#endregion + #endregion + + public class FakeClipboard : ClipboardBase { + public Exception FakeException = null; + + string contents = string.Empty; + + bool isSupportedAlwaysFalse = false; + + public override bool IsSupported => !isSupportedAlwaysFalse; + + public FakeClipboard (bool fakeClipboardThrowsNotSupportedException = false, bool isSupportedAlwaysFalse = false) + { + this.isSupportedAlwaysFalse = isSupportedAlwaysFalse; + if (fakeClipboardThrowsNotSupportedException) { + FakeException = new NotSupportedException ("Fake clipboard exception"); + } + } + + protected override string GetClipboardDataImpl () + { + if (FakeException != null) { + throw FakeException; + } + return contents; + } + + protected override void SetClipboardDataImpl (string text) + { + if (FakeException != null) { + throw FakeException; + } + contents = text; + } + } #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member } diff --git a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriverBehaviors.cs b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriverBehaviors.cs deleted file mode 100644 index 1ba2aa8cbc..0000000000 --- a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriverBehaviors.cs +++ /dev/null @@ -1,26 +0,0 @@ -// -// FakeDriver.cs: A fake ConsoleDriver for unit tests. -// -using System.Diagnostics; - -// Alias Console to MockConsole so we don't accidentally use Console - -namespace Terminal.Gui { - public class FakeDriverBehaviors { - - public bool UseFakeClipboard { get; internal set; } - public bool FakeClipboardAlwaysThrowsNotSupportedException { get; internal set; } - public bool FakeClipboardIsSupportedAlwaysFalse { get; internal set; } - - public FakeDriverBehaviors (bool useFakeClipboard = false, bool fakeClipboardAlwaysThrowsNotSupportedException = false, bool fakeClipboardIsSupportedAlwaysTrue = false) - { - UseFakeClipboard = useFakeClipboard; - FakeClipboardAlwaysThrowsNotSupportedException = fakeClipboardAlwaysThrowsNotSupportedException; - FakeClipboardIsSupportedAlwaysFalse = fakeClipboardIsSupportedAlwaysTrue; - - // double check usage is correct - Debug.Assert (useFakeClipboard == false && fakeClipboardAlwaysThrowsNotSupportedException == false); - Debug.Assert (useFakeClipboard == false && fakeClipboardIsSupportedAlwaysTrue == false); - } - } -} \ No newline at end of file diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver.cs index 4a3c48e828..6d9fa4930a 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs @@ -909,7 +909,8 @@ public override void UpdateScreen () int redrawAttr = -1; var lastCol = -1; - Console.CursorVisible = false; + GetCursorVisibility (out CursorVisibility savedVisibitity); + SetCursorVisibility (CursorVisibility.Invisible); for (int row = top; row < rows; row++) { if (Console.WindowHeight < 1) { @@ -967,6 +968,7 @@ public override void UpdateScreen () } } SetCursorPosition (0, 0); + SetCursorVisibility (savedVisibitity); } void SetVirtualCursorPosition (int col, int row) @@ -1444,7 +1446,13 @@ public override bool GetCursorVisibility (out CursorVisibility visibility) public override bool SetCursorVisibility (CursorVisibility visibility) { savedCursorVisibility = visibility; - return Console.CursorVisible = visibility == CursorVisibility.Default; + var isVisible = Console.CursorVisible = visibility == CursorVisibility.Default; + if (isVisible) { + Console.Out.Write ("\x1b[?25h"); + } else { + Console.Out.Write ("\x1b[?25l"); + } + return isVisible; } /// diff --git a/Terminal.Gui/Terminal.Gui.csproj b/Terminal.Gui/Terminal.Gui.csproj index 8934f57dbb..cb5731ae6c 100644 --- a/Terminal.Gui/Terminal.Gui.csproj +++ b/Terminal.Gui/Terminal.Gui.csproj @@ -5,7 +5,7 @@ TRACE;DEBUG_IDISPOSABLE portable - CA1034 + CS1574 diff --git a/Terminal.Gui/Views/Toplevel.cs b/Terminal.Gui/Views/Toplevel.cs index c207614777..c1ba0d0df9 100644 --- a/Terminal.Gui/Views/Toplevel.cs +++ b/Terminal.Gui/Views/Toplevel.cs @@ -75,23 +75,23 @@ public partial class Toplevel : View { public event EventHandler AllChildClosed; /// - /// Invoked when the Toplevel's is being closed by + /// Invoked when the Toplevel's is being closed by /// . /// public event EventHandler Closing; /// - /// Invoked when the Toplevel's is closed by . + /// Invoked when the Toplevel's is closed by . /// public event EventHandler Closed; /// - /// Invoked when a child Toplevel's has been loaded. + /// Invoked when a child Toplevel's has been loaded. /// public event EventHandler ChildLoaded; /// - /// Invoked when a cjhild Toplevel's has been unloaded. + /// Invoked when a cjhild Toplevel's has been unloaded. /// public event EventHandler ChildUnloaded; @@ -174,7 +174,7 @@ internal virtual void OnReady () } /// - /// Called from before the is disposed. + /// Called from before the is disposed. /// internal virtual void OnUnloaded () { From fe496b14ff58125738c594cc92d4accd2a31faa2 Mon Sep 17 00:00:00 2001 From: tznind Date: Tue, 23 May 2023 07:46:25 +0100 Subject: [PATCH 8/9] Change to file scoped namespaces and revert renames - LineCanvasCell back to just Cell - ApplicationRunState back to just RunState --- Terminal.Gui/Application.cs | 34 +- Terminal.Gui/ApplicationRunState.cs | 79 ---- .../Configuration/ScopeJsonConverter.cs | 214 +++++------ Terminal.Gui/Configuration/ThemeManager.cs | 358 +++++++++--------- Terminal.Gui/Drawing/Cell.cs | 20 + Terminal.Gui/Drawing/LineCanvas.cs | 8 +- Terminal.Gui/Drawing/LineCanvasCell.cs | 21 - Terminal.Gui/RunState.cs | 79 ++++ Terminal.Gui/RunStateEventArgs.cs | 6 +- Terminal.Gui/Views/Toplevel.cs | 30 +- UICatalog/UICatalog.cs | 4 +- UnitTests/Application/ApplicationTests.cs | 6 +- UnitTests/Application/RunStateTests.cs | 12 +- UnitTests/Dialogs/DialogTests.cs | 24 +- UnitTests/View/Layout/PosTests.cs | 4 +- UnitTests/Views/OverlappedTests.cs | 2 +- 16 files changed, 449 insertions(+), 452 deletions(-) delete mode 100644 Terminal.Gui/ApplicationRunState.cs create mode 100644 Terminal.Gui/Drawing/Cell.cs delete mode 100644 Terminal.Gui/Drawing/LineCanvasCell.cs create mode 100644 Terminal.Gui/RunState.cs diff --git a/Terminal.Gui/Application.cs b/Terminal.Gui/Application.cs index d8871d53f5..f18149b2a5 100644 --- a/Terminal.Gui/Application.cs +++ b/Terminal.Gui/Application.cs @@ -304,40 +304,40 @@ static void ResetState () #region Run (Begin, Run, End) /// - /// Notify that a new was created ( was called). The token is created in + /// Notify that a new was created ( was called). The token is created in /// and this event will be fired before that function exits. /// /// /// If is callers to /// must also subscribe to - /// and manually dispose of the token when the application is done. + /// and manually dispose of the token when the application is done. /// public static event EventHandler NotifyNewRunState; /// - /// Notify that a existent is stopping ( was called). + /// Notify that a existent is stopping ( was called). /// /// /// If is callers to /// must also subscribe to - /// and manually dispose of the token when the application is done. + /// and manually dispose of the token when the application is done. /// public static event EventHandler NotifyStopRunState; /// /// Building block API: Prepares the provided for execution. /// - /// The handle that needs to be passed to the method upon completion. + /// The handle that needs to be passed to the method upon completion. /// The to prepare execution for. /// /// This method prepares the provided for running with the focus, /// it adds this to the list of s, sets up the to process the /// event, lays out the Subviews, focuses the first element, and draws the /// in the screen. This is usually followed by executing - /// the method, and then the method upon termination which will + /// the method, and then the method upon termination which will /// undo these changes. /// - public static ApplicationRunState Begin (Toplevel Toplevel) + public static RunState Begin (Toplevel Toplevel) { if (Toplevel == null) { throw new ArgumentNullException (nameof (Toplevel)); @@ -348,7 +348,7 @@ public static ApplicationRunState Begin (Toplevel Toplevel) // Ensure the mouse is ungrabed. _mouseGrabView = null; - var rs = new ApplicationRunState (Toplevel); + var rs = new RunState (Toplevel); // View implements ISupportInitializeNotification which is derived from ISupportInitialize if (!Toplevel.IsInitialized) { @@ -499,20 +499,20 @@ public static void Run (Func errorHandler = null) /// To make a stop execution, call . /// /// - /// Calling is equivalent to calling , followed by , - /// and then calling . + /// Calling is equivalent to calling , followed by , + /// and then calling . /// /// /// Alternatively, to have a program control the main loop and /// process events manually, call to set things up manually and then - /// repeatedly call with the wait parameter set to false. By doing this - /// the method will only process any pending events, timers, idle handlers and + /// repeatedly call with the wait parameter set to false. By doing this + /// the method will only process any pending events, timers, idle handlers and /// then return control immediately. /// /// /// RELEASE builds only: When is any exeptions will be rethrown. /// Otherwise, if will be called. If - /// returns the will resume; otherwise + /// returns the will resume; otherwise /// this method will exit. /// /// @@ -638,7 +638,7 @@ public override void Send (SendOrPostCallback d, object state) /// The state returned by the method. /// By default this is which will execute the loop waiting for events, /// if set to , a single iteration will execute. - public static void RunLoop (ApplicationRunState state, bool wait = true) + public static void RunLoop (RunState state, bool wait = true) { if (state == null) throw new ArgumentNullException (nameof (state)); @@ -662,7 +662,7 @@ public static void RunLoop (ApplicationRunState state, bool wait = true) /// will return after a single iteration. /// Set to if this is the first run loop iteration. Upon return, /// it will be set to if at least one iteration happened. - public static void RunMainLoopIteration (ref ApplicationRunState state, bool wait, ref bool firstIteration) + public static void RunMainLoopIteration (ref RunState state, bool wait, ref bool firstIteration) { if (MainLoop.EventsPending (wait)) { // Notify Toplevel it's ready @@ -825,8 +825,8 @@ static void OnNotifyStopRunState (Toplevel top) /// /// Building block API: completes the execution of a that was started with . /// - /// The returned by the method. - public static void End (ApplicationRunState runState) + /// The returned by the method. + public static void End (RunState runState) { if (runState == null) throw new ArgumentNullException (nameof (runState)); diff --git a/Terminal.Gui/ApplicationRunState.cs b/Terminal.Gui/ApplicationRunState.cs deleted file mode 100644 index cd9e188706..0000000000 --- a/Terminal.Gui/ApplicationRunState.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Terminal.Gui { - /// - /// The execution state for a view. - /// - public class ApplicationRunState : IDisposable { - /// - /// Initializes a new class. - /// - /// - public ApplicationRunState (Toplevel view) - { - Toplevel = view; - } - /// - /// The belonging to this . - /// - public Toplevel Toplevel { get; internal set; } - -#if DEBUG_IDISPOSABLE - /// - /// For debug (see DEBUG_IDISPOSABLE define) purposes to verify objects are being disposed properly - /// - public bool WasDisposed = false; - - /// - /// For debug (see DEBUG_IDISPOSABLE define) purposes to verify objects are being disposed properly - /// - public int DisposedCount = 0; - - /// - /// For debug (see DEBUG_IDISPOSABLE define) purposes; the runstate instances that have been created - /// - public static List Instances = new List (); - - /// - /// Creates a new RunState object. - /// - public ApplicationRunState () - { - Instances.Add (this); - } -#endif - - /// - /// Releases all resource used by the object. - /// - /// - /// Call when you are finished using the . - /// - /// - /// method leaves the in an unusable state. After - /// calling , you must release all references to the - /// so the garbage collector can reclaim the memory that the - /// was occupying. - /// - public void Dispose () - { - Dispose (true); - GC.SuppressFinalize (this); -#if DEBUG_IDISPOSABLE - WasDisposed = true; -#endif - } - - /// - /// Releases all resource used by the object. - /// - /// If set to we are disposing and should dispose held objects. - protected virtual void Dispose (bool disposing) - { - if (Toplevel != null && disposing) { - throw new InvalidOperationException ("You must clean up (Dispose) the Toplevel before calling Application.RunState.Dispose"); - } - } - } -} diff --git a/Terminal.Gui/Configuration/ScopeJsonConverter.cs b/Terminal.Gui/Configuration/ScopeJsonConverter.cs index edd5419066..036f772413 100644 --- a/Terminal.Gui/Configuration/ScopeJsonConverter.cs +++ b/Terminal.Gui/Configuration/ScopeJsonConverter.cs @@ -6,135 +6,135 @@ #nullable enable -namespace Terminal.Gui { - /// - /// Converts instances to/from JSON. Does all the heavy lifting of reading/writing - /// config data to/from JSON documents. - /// - /// - internal class ScopeJsonConverter : JsonConverter where scopeT : Scope { - // See: https://stackoverflow.com/questions/60830084/how-to-pass-an-argument-by-reference-using-reflection - internal abstract class ReadHelper { - public abstract object? Read (ref Utf8JsonReader reader, Type type, JsonSerializerOptions options); - } +namespace Terminal.Gui; + +/// +/// Converts instances to/from JSON. Does all the heavy lifting of reading/writing +/// config data to/from JSON documents. +/// +/// +internal class ScopeJsonConverter : JsonConverter where scopeT : Scope { + // See: https://stackoverflow.com/questions/60830084/how-to-pass-an-argument-by-reference-using-reflection + internal abstract class ReadHelper { + public abstract object? Read (ref Utf8JsonReader reader, Type type, JsonSerializerOptions options); + } + + internal class ReadHelper : ReadHelper { + private readonly ReadDelegate _readDelegate; + private delegate converterT ReadDelegate (ref Utf8JsonReader reader, Type type, JsonSerializerOptions options); + public ReadHelper (object converter) + => _readDelegate = (ReadDelegate)Delegate.CreateDelegate (typeof (ReadDelegate), converter, "Read"); + public override object? Read (ref Utf8JsonReader reader, Type type, JsonSerializerOptions options) + => _readDelegate.Invoke (ref reader, type, options); + } - internal class ReadHelper : ReadHelper { - private readonly ReadDelegate _readDelegate; - private delegate converterT ReadDelegate (ref Utf8JsonReader reader, Type type, JsonSerializerOptions options); - public ReadHelper (object converter) - => _readDelegate = (ReadDelegate)Delegate.CreateDelegate (typeof (ReadDelegate), converter, "Read"); - public override object? Read (ref Utf8JsonReader reader, Type type, JsonSerializerOptions options) - => _readDelegate.Invoke (ref reader, type, options); + public override scopeT Read (ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType != JsonTokenType.StartObject) { + throw new JsonException ($"Expected a JSON object (\"{{ \"propName\" : ... }}\"), but got \"{reader.TokenType}\"."); } - public override scopeT Read (ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - if (reader.TokenType != JsonTokenType.StartObject) { - throw new JsonException ($"Expected a JSON object (\"{{ \"propName\" : ... }}\"), but got \"{reader.TokenType}\"."); + var scope = (scopeT)Activator.CreateInstance (typeof (scopeT))!; + while (reader.Read ()) { + if (reader.TokenType == JsonTokenType.EndObject) { + return scope!; } + if (reader.TokenType != JsonTokenType.PropertyName) { + throw new JsonException ($"Expected a JSON property name, but got \"{reader.TokenType}\"."); + } + var propertyName = reader.GetString (); + reader.Read (); - var scope = (scopeT)Activator.CreateInstance (typeof (scopeT))!; - while (reader.Read ()) { - if (reader.TokenType == JsonTokenType.EndObject) { - return scope!; - } - if (reader.TokenType != JsonTokenType.PropertyName) { - throw new JsonException ($"Expected a JSON property name, but got \"{reader.TokenType}\"."); - } - var propertyName = reader.GetString (); - reader.Read (); - - if (propertyName != null && scope!.TryGetValue (propertyName, out var configProp)) { - // This property name was found in the Scope's ScopeProperties dictionary - // Figure out if it needs a JsonConverter and if so, create one - var propertyType = configProp?.PropertyInfo?.PropertyType!; - if (configProp?.PropertyInfo?.GetCustomAttribute (typeof (JsonConverterAttribute)) is JsonConverterAttribute jca) { - var converter = Activator.CreateInstance (jca.ConverterType!)!; - if (converter.GetType ().BaseType == typeof (JsonConverterFactory)) { - var factory = (JsonConverterFactory)converter; - if (propertyType != null && factory.CanConvert (propertyType)) { - converter = factory.CreateConverter (propertyType, options); - } - } - var readHelper = Activator.CreateInstance ((Type?)typeof (ReadHelper<>).MakeGenericType (typeof (scopeT), propertyType!)!, converter) as ReadHelper; - try { - scope! [propertyName].PropertyValue = readHelper?.Read (ref reader, propertyType!, options); - } catch (NotSupportedException e) { - throw new JsonException ($"Error reading property \"{propertyName}\" of type \"{propertyType?.Name}\".", e); - } - } else { - try { - scope! [propertyName].PropertyValue = JsonSerializer.Deserialize (ref reader, propertyType!, options); - } catch (Exception ex) { - System.Diagnostics.Debug.WriteLine ($"scopeT Read: {ex}"); + if (propertyName != null && scope!.TryGetValue (propertyName, out var configProp)) { + // This property name was found in the Scope's ScopeProperties dictionary + // Figure out if it needs a JsonConverter and if so, create one + var propertyType = configProp?.PropertyInfo?.PropertyType!; + if (configProp?.PropertyInfo?.GetCustomAttribute (typeof (JsonConverterAttribute)) is JsonConverterAttribute jca) { + var converter = Activator.CreateInstance (jca.ConverterType!)!; + if (converter.GetType ().BaseType == typeof (JsonConverterFactory)) { + var factory = (JsonConverterFactory)converter; + if (propertyType != null && factory.CanConvert (propertyType)) { + converter = factory.CreateConverter (propertyType, options); } } + var readHelper = Activator.CreateInstance ((Type?)typeof (ReadHelper<>).MakeGenericType (typeof (scopeT), propertyType!)!, converter) as ReadHelper; + try { + scope! [propertyName].PropertyValue = readHelper?.Read (ref reader, propertyType!, options); + } catch (NotSupportedException e) { + throw new JsonException ($"Error reading property \"{propertyName}\" of type \"{propertyType?.Name}\".", e); + } } else { - // It is not a config property. Maybe it's just a property on the Scope with [JsonInclude] - // like ScopeSettings.$schema... - var property = scope!.GetType ().GetProperties ().Where (p => { - var jia = p.GetCustomAttribute (typeof (JsonIncludeAttribute)) as JsonIncludeAttribute; - if (jia != null) { - var jpna = p.GetCustomAttribute (typeof (JsonPropertyNameAttribute)) as JsonPropertyNameAttribute; - if (jpna?.Name == propertyName) { - // Bit of a hack, modifying propertyName in an enumerator... - propertyName = p.Name; - return true; - } - - return p.Name == propertyName; + try { + scope! [propertyName].PropertyValue = JsonSerializer.Deserialize (ref reader, propertyType!, options); + } catch (Exception ex) { + System.Diagnostics.Debug.WriteLine ($"scopeT Read: {ex}"); + } + } + } else { + // It is not a config property. Maybe it's just a property on the Scope with [JsonInclude] + // like ScopeSettings.$schema... + var property = scope!.GetType ().GetProperties ().Where (p => { + var jia = p.GetCustomAttribute (typeof (JsonIncludeAttribute)) as JsonIncludeAttribute; + if (jia != null) { + var jpna = p.GetCustomAttribute (typeof (JsonPropertyNameAttribute)) as JsonPropertyNameAttribute; + if (jpna?.Name == propertyName) { + // Bit of a hack, modifying propertyName in an enumerator... + propertyName = p.Name; + return true; } - return false; - }).FirstOrDefault (); - if (property != null) { - var prop = scope.GetType ().GetProperty (propertyName!)!; - prop.SetValue (scope, JsonSerializer.Deserialize (ref reader, prop.PropertyType, options)); - } else { - // Unknown property - throw new JsonException ($"Unknown property name \"{propertyName}\"."); + return p.Name == propertyName; } + return false; + }).FirstOrDefault (); + + if (property != null) { + var prop = scope.GetType ().GetProperty (propertyName!)!; + prop.SetValue (scope, JsonSerializer.Deserialize (ref reader, prop.PropertyType, options)); + } else { + // Unknown property + throw new JsonException ($"Unknown property name \"{propertyName}\"."); } } - throw new JsonException (); } + throw new JsonException (); + } - public override void Write (Utf8JsonWriter writer, scopeT scope, JsonSerializerOptions options) - { - writer.WriteStartObject (); + public override void Write (Utf8JsonWriter writer, scopeT scope, JsonSerializerOptions options) + { + writer.WriteStartObject (); - var properties = scope!.GetType ().GetProperties ().Where (p => p.GetCustomAttribute (typeof (JsonIncludeAttribute)) != null); - foreach (var p in properties) { - writer.WritePropertyName (ConfigProperty.GetJsonPropertyName (p)); - JsonSerializer.Serialize (writer, scope.GetType ().GetProperty (p.Name)?.GetValue (scope), options); - } + var properties = scope!.GetType ().GetProperties ().Where (p => p.GetCustomAttribute (typeof (JsonIncludeAttribute)) != null); + foreach (var p in properties) { + writer.WritePropertyName (ConfigProperty.GetJsonPropertyName (p)); + JsonSerializer.Serialize (writer, scope.GetType ().GetProperty (p.Name)?.GetValue (scope), options); + } - foreach (var p in from p in scope - .Where (cp => - cp.Value.PropertyInfo?.GetCustomAttribute (typeof (SerializableConfigurationProperty)) is - SerializableConfigurationProperty scp && scp?.Scope == typeof (scopeT)) - where p.Value.PropertyValue != null - select p) { + foreach (var p in from p in scope + .Where (cp => + cp.Value.PropertyInfo?.GetCustomAttribute (typeof (SerializableConfigurationProperty)) is + SerializableConfigurationProperty scp && scp?.Scope == typeof (scopeT)) + where p.Value.PropertyValue != null + select p) { - writer.WritePropertyName (p.Key); - var propertyType = p.Value.PropertyInfo?.PropertyType; + writer.WritePropertyName (p.Key); + var propertyType = p.Value.PropertyInfo?.PropertyType; - if (propertyType != null && p.Value.PropertyInfo?.GetCustomAttribute (typeof (JsonConverterAttribute)) is JsonConverterAttribute jca) { - var converter = Activator.CreateInstance (jca.ConverterType!)!; - if (converter.GetType ().BaseType == typeof (JsonConverterFactory)) { - var factory = (JsonConverterFactory)converter; - if (factory.CanConvert (propertyType)) { - converter = factory.CreateConverter (propertyType, options)!; - } + if (propertyType != null && p.Value.PropertyInfo?.GetCustomAttribute (typeof (JsonConverterAttribute)) is JsonConverterAttribute jca) { + var converter = Activator.CreateInstance (jca.ConverterType!)!; + if (converter.GetType ().BaseType == typeof (JsonConverterFactory)) { + var factory = (JsonConverterFactory)converter; + if (factory.CanConvert (propertyType)) { + converter = factory.CreateConverter (propertyType, options)!; } - if (p.Value.PropertyValue != null) { - converter.GetType ().GetMethod ("Write")?.Invoke (converter, new object [] { writer, p.Value.PropertyValue, options }); - } - } else { - JsonSerializer.Serialize (writer, p.Value.PropertyValue, options); } + if (p.Value.PropertyValue != null) { + converter.GetType ().GetMethod ("Write")?.Invoke (converter, new object [] { writer, p.Value.PropertyValue, options }); + } + } else { + JsonSerializer.Serialize (writer, p.Value.PropertyValue, options); } - writer.WriteEndObject (); } + writer.WriteEndObject (); } } diff --git a/Terminal.Gui/Configuration/ThemeManager.cs b/Terminal.Gui/Configuration/ThemeManager.cs index 1886e65576..f51c75b7d4 100644 --- a/Terminal.Gui/Configuration/ThemeManager.cs +++ b/Terminal.Gui/Configuration/ThemeManager.cs @@ -6,204 +6,202 @@ #nullable enable -namespace Terminal.Gui { +namespace Terminal.Gui; + +/// +/// Contains a dictionary of the s for a Terminal.Gui application. +/// +/// +/// +/// A Theme is a collection of settings that are named. The default theme is named "Default". +/// +/// +/// The property is used to detemrine the currently active theme. +/// +/// +/// +/// is a singleton class. It is created when the first property is accessed. +/// Accessing is the same as accessing . +/// +/// +/// "Themes": [ +/// { +/// "Default": { +/// "ColorSchemes": [ +/// { +/// "TopLevel": { +/// "Normal": { +/// "Foreground": "BrightGreen", +/// "Background": "Black" +/// }, +/// "Focus": { +/// "Foreground": "White", +/// "Background": "Cyan" +/// +/// }, +/// "HotNormal": { +/// "Foreground": "Brown", +/// "Background": "Black" +/// +/// }, +/// "HotFocus": { +/// "Foreground": "Blue", +/// "Background": "Cyan" +/// }, +/// "Disabled": { +/// "Foreground": "DarkGray", +/// "Background": "Black" +/// +/// } +/// } +/// } +/// +public class ThemeManager : IDictionary { + private static readonly ThemeManager _instance = new ThemeManager (); + static ThemeManager () { } // Make sure it's truly lazy + private ThemeManager () { } // Prevent instantiation outside /// - /// Contains a dictionary of the s for a Terminal.Gui application. + /// Class is a singleton... /// - /// - /// - /// A Theme is a collection of settings that are named. The default theme is named "Default". - /// - /// - /// The property is used to detemrine the currently active theme. - /// - /// - /// - /// is a singleton class. It is created when the first property is accessed. - /// Accessing is the same as accessing . - /// - /// - /// "Themes": [ - /// { - /// "Default": { - /// "ColorSchemes": [ - /// { - /// "TopLevel": { - /// "Normal": { - /// "Foreground": "BrightGreen", - /// "Background": "Black" - /// }, - /// "Focus": { - /// "Foreground": "White", - /// "Background": "Cyan" - /// - /// }, - /// "HotNormal": { - /// "Foreground": "Brown", - /// "Background": "Black" - /// - /// }, - /// "HotFocus": { - /// "Foreground": "Blue", - /// "Background": "Cyan" - /// }, - /// "Disabled": { - /// "Foreground": "DarkGray", - /// "Background": "Black" - /// - /// } - /// } - /// } - /// - public class ThemeManager : IDictionary { - private static readonly ThemeManager _instance = new ThemeManager (); - static ThemeManager () { } // Make sure it's truly lazy - private ThemeManager () { } // Prevent instantiation outside - - /// - /// Class is a singleton... - /// - public static ThemeManager Instance { get { return _instance; } } - - private static string _theme = string.Empty; - - /// - /// The currently selected theme. This is the internal version; see . - /// - [JsonInclude, SerializableConfigurationProperty (Scope = typeof (SettingsScope), OmitClassName = true), JsonPropertyName ("Theme")] - internal static string SelectedTheme { - get => _theme; - set { - var oldTheme = _theme; - _theme = value; - if (oldTheme != _theme && - ConfigurationManager.Settings! ["Themes"]?.PropertyValue is Dictionary themes && - themes.ContainsKey (_theme)) { - ConfigurationManager.Settings! ["Theme"].PropertyValue = _theme; - Instance.OnThemeChanged (oldTheme); - } - } - } + public static ThemeManager Instance { get { return _instance; } } + + private static string _theme = string.Empty; - /// - /// Gets or sets the currently selected theme. The value is persisted to the "Theme" - /// property. - /// - [JsonIgnore] - public string Theme { - get => ThemeManager.SelectedTheme; - set { - ThemeManager.SelectedTheme = value; + /// + /// The currently selected theme. This is the internal version; see . + /// + [JsonInclude, SerializableConfigurationProperty (Scope = typeof (SettingsScope), OmitClassName = true), JsonPropertyName ("Theme")] + internal static string SelectedTheme { + get => _theme; + set { + var oldTheme = _theme; + _theme = value; + if (oldTheme != _theme && + ConfigurationManager.Settings! ["Themes"]?.PropertyValue is Dictionary themes && + themes.ContainsKey (_theme)) { + ConfigurationManager.Settings! ["Theme"].PropertyValue = _theme; + Instance.OnThemeChanged (oldTheme); } } + } - /// - /// Called when the selected theme has changed. Fires the event. - /// - internal void OnThemeChanged (string theme) - { - Debug.WriteLine ($"Themes.OnThemeChanged({theme}) -> {Theme}"); - ThemeChanged?.Invoke (this, new ThemeManagerEventArgs (theme)); + /// + /// Gets or sets the currently selected theme. The value is persisted to the "Theme" + /// property. + /// + [JsonIgnore] + public string Theme { + get => ThemeManager.SelectedTheme; + set { + ThemeManager.SelectedTheme = value; } + } - /// - /// Event fired he selected theme has changed. - /// application. - /// - public event EventHandler? ThemeChanged; - - /// - /// Holds the definitions. - /// - [JsonInclude, JsonConverter (typeof (DictionaryJsonConverter))] - [SerializableConfigurationProperty (Scope = typeof (SettingsScope), OmitClassName = true)] - public static Dictionary? Themes { - get => ConfigurationManager.Settings? ["Themes"]?.PropertyValue as Dictionary; // themes ?? new Dictionary (); - set { - //if (themes == null || value == null) { - // themes = value; - //} else { - // themes = (Dictionary)DeepMemberwiseCopy (value!, themes!)!; - //} - ConfigurationManager.Settings! ["Themes"].PropertyValue = value; - } - } + /// + /// Called when the selected theme has changed. Fires the event. + /// + internal void OnThemeChanged (string theme) + { + Debug.WriteLine ($"Themes.OnThemeChanged({theme}) -> {Theme}"); + ThemeChanged?.Invoke (this, new ThemeManagerEventArgs (theme)); + } - internal static void Reset () - { - Debug.WriteLine ($"Themes.Reset()"); + /// + /// Event fired he selected theme has changed. + /// application. + /// + public event EventHandler? ThemeChanged; - Themes?.Clear (); - SelectedTheme = string.Empty; + /// + /// Holds the definitions. + /// + [JsonInclude, JsonConverter (typeof (DictionaryJsonConverter))] + [SerializableConfigurationProperty (Scope = typeof (SettingsScope), OmitClassName = true)] + public static Dictionary? Themes { + get => ConfigurationManager.Settings? ["Themes"]?.PropertyValue as Dictionary; // themes ?? new Dictionary (); + set { + //if (themes == null || value == null) { + // themes = value; + //} else { + // themes = (Dictionary)DeepMemberwiseCopy (value!, themes!)!; + //} + ConfigurationManager.Settings! ["Themes"].PropertyValue = value; } + } - internal static void GetHardCodedDefaults () - { - Debug.WriteLine ($"Themes.GetHardCodedDefaults()"); - var theme = new ThemeScope (); - theme.RetrieveValues (); + internal static void Reset () + { + Debug.WriteLine ($"Themes.Reset()"); - Themes = new Dictionary (StringComparer.InvariantCultureIgnoreCase) { { "Default", theme } }; - SelectedTheme = "Default"; - } + Themes?.Clear (); + SelectedTheme = string.Empty; + } - #region IDictionary -#pragma warning disable 1591 + internal static void GetHardCodedDefaults () + { + Debug.WriteLine ($"Themes.GetHardCodedDefaults()"); + var theme = new ThemeScope (); + theme.RetrieveValues (); - public ICollection Keys => ((IDictionary)Themes!).Keys; - public ICollection Values => ((IDictionary)Themes!).Values; - public int Count => ((ICollection>)Themes!).Count; - public bool IsReadOnly => ((ICollection>)Themes!).IsReadOnly; - public ThemeScope this [string key] { get => ((IDictionary)Themes!) [key]; set => ((IDictionary)Themes!) [key] = value; } - public void Add (string key, ThemeScope value) - { - ((IDictionary)Themes!).Add (key, value); - } - public bool ContainsKey (string key) - { - return ((IDictionary)Themes!).ContainsKey (key); - } - public bool Remove (string key) - { - return ((IDictionary)Themes!).Remove (key); - } - public bool TryGetValue (string key, out ThemeScope value) - { - return ((IDictionary)Themes!).TryGetValue (key, out value!); - } - public void Add (KeyValuePair item) - { - ((ICollection>)Themes!).Add (item); - } - public void Clear () - { - ((ICollection>)Themes!).Clear (); - } - public bool Contains (KeyValuePair item) - { - return ((ICollection>)Themes!).Contains (item); - } - public void CopyTo (KeyValuePair [] array, int arrayIndex) - { - ((ICollection>)Themes!).CopyTo (array, arrayIndex); - } - public bool Remove (KeyValuePair item) - { - return ((ICollection>)Themes!).Remove (item); - } - public IEnumerator> GetEnumerator () - { - return ((IEnumerable>)Themes!).GetEnumerator (); - } + Themes = new Dictionary (StringComparer.InvariantCultureIgnoreCase) { { "Default", theme } }; + SelectedTheme = "Default"; + } - IEnumerator IEnumerable.GetEnumerator () - { - return ((IEnumerable)Themes!).GetEnumerator (); - } -#pragma warning restore 1591 + #region IDictionary +#pragma warning disable 1591 - #endregion + public ICollection Keys => ((IDictionary)Themes!).Keys; + public ICollection Values => ((IDictionary)Themes!).Values; + public int Count => ((ICollection>)Themes!).Count; + public bool IsReadOnly => ((ICollection>)Themes!).IsReadOnly; + public ThemeScope this [string key] { get => ((IDictionary)Themes!) [key]; set => ((IDictionary)Themes!) [key] = value; } + public void Add (string key, ThemeScope value) + { + ((IDictionary)Themes!).Add (key, value); } + public bool ContainsKey (string key) + { + return ((IDictionary)Themes!).ContainsKey (key); + } + public bool Remove (string key) + { + return ((IDictionary)Themes!).Remove (key); + } + public bool TryGetValue (string key, out ThemeScope value) + { + return ((IDictionary)Themes!).TryGetValue (key, out value!); + } + public void Add (KeyValuePair item) + { + ((ICollection>)Themes!).Add (item); + } + public void Clear () + { + ((ICollection>)Themes!).Clear (); + } + public bool Contains (KeyValuePair item) + { + return ((ICollection>)Themes!).Contains (item); + } + public void CopyTo (KeyValuePair [] array, int arrayIndex) + { + ((ICollection>)Themes!).CopyTo (array, arrayIndex); + } + public bool Remove (KeyValuePair item) + { + return ((ICollection>)Themes!).Remove (item); + } + public IEnumerator> GetEnumerator () + { + return ((IEnumerable>)Themes!).GetEnumerator (); + } + + IEnumerator IEnumerable.GetEnumerator () + { + return ((IEnumerable)Themes!).GetEnumerator (); + } +#pragma warning restore 1591 + #endregion } \ No newline at end of file diff --git a/Terminal.Gui/Drawing/Cell.cs b/Terminal.Gui/Drawing/Cell.cs new file mode 100644 index 0000000000..8d511b5ded --- /dev/null +++ b/Terminal.Gui/Drawing/Cell.cs @@ -0,0 +1,20 @@ +using System.Text; + + +namespace Terminal.Gui; + +/// +/// Represents a single row/column within the . Includes the glyph and the foreground/background colors. +/// +public class Cell { + /// + /// The glyph to draw. + /// + public Rune? Rune { get; set; } + + /// + /// The foreground color to draw the glyph with. + /// + public Attribute? Attribute { get; set; } + +} diff --git a/Terminal.Gui/Drawing/LineCanvas.cs b/Terminal.Gui/Drawing/LineCanvas.cs index 0dd4d3cb31..5b09af2333 100644 --- a/Terminal.Gui/Drawing/LineCanvas.cs +++ b/Terminal.Gui/Drawing/LineCanvas.cs @@ -213,9 +213,9 @@ public Dictionary GetMap (Rect inArea) /// so that all lines connect up with the appropriate intersection symbols. /// /// A map of all the points within the canvas. - public Dictionary GetCellMap () + public Dictionary GetCellMap () { - var map = new Dictionary (); + var map = new Dictionary (); // walk through each pixel of the bitmap for (int y = Bounds.Y; y < Bounds.Y + Bounds.Height; y++) { @@ -528,13 +528,13 @@ public override void SetGlyphs () } - private LineCanvasCell GetCellForIntersects (ConsoleDriver driver, IntersectionDefinition [] intersects) + private Cell GetCellForIntersects (ConsoleDriver driver, IntersectionDefinition [] intersects) { if (!intersects.Any ()) { return null; } - var cell = new LineCanvasCell (); + var cell = new Cell (); cell.Rune = GetRuneForIntersects (driver, intersects); cell.Attribute = GetAttributeForIntersects (intersects); return cell; diff --git a/Terminal.Gui/Drawing/LineCanvasCell.cs b/Terminal.Gui/Drawing/LineCanvasCell.cs deleted file mode 100644 index ff3ab77e74..0000000000 --- a/Terminal.Gui/Drawing/LineCanvasCell.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Text; - - -namespace Terminal.Gui { - - /// - /// Represents a single row/column within the . Includes the glyph and the foreground/background colors. - /// - public class LineCanvasCell { - /// - /// The glyph to draw. - /// - public Rune? Rune { get; set; } - - /// - /// The foreground color to draw the glyph with. - /// - public Attribute? Attribute { get; set; } - - } -} diff --git a/Terminal.Gui/RunState.cs b/Terminal.Gui/RunState.cs new file mode 100644 index 0000000000..c10448ec28 --- /dev/null +++ b/Terminal.Gui/RunState.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; + +namespace Terminal.Gui; + +/// +/// The execution state for a view. +/// +public class RunState : IDisposable { + /// + /// Initializes a new class. + /// + /// + public RunState (Toplevel view) + { + Toplevel = view; + } + /// + /// The belonging to this . + /// + public Toplevel Toplevel { get; internal set; } + +#if DEBUG_IDISPOSABLE + /// + /// For debug (see DEBUG_IDISPOSABLE define) purposes to verify objects are being disposed properly + /// + public bool WasDisposed = false; + + /// + /// For debug (see DEBUG_IDISPOSABLE define) purposes to verify objects are being disposed properly + /// + public int DisposedCount = 0; + + /// + /// For debug (see DEBUG_IDISPOSABLE define) purposes; the runstate instances that have been created + /// + public static List Instances = new List (); + + /// + /// Creates a new RunState object. + /// + public RunState () + { + Instances.Add (this); + } +#endif + + /// + /// Releases all resource used by the object. + /// + /// + /// Call when you are finished using the . + /// + /// + /// method leaves the in an unusable state. After + /// calling , you must release all references to the + /// so the garbage collector can reclaim the memory that the + /// was occupying. + /// + public void Dispose () + { + Dispose (true); + GC.SuppressFinalize (this); +#if DEBUG_IDISPOSABLE + WasDisposed = true; +#endif + } + + /// + /// Releases all resource used by the object. + /// + /// If set to we are disposing and should dispose held objects. + protected virtual void Dispose (bool disposing) + { + if (Toplevel != null && disposing) { + throw new InvalidOperationException ("You must clean up (Dispose) the Toplevel before calling Application.RunState.Dispose"); + } + } +} diff --git a/Terminal.Gui/RunStateEventArgs.cs b/Terminal.Gui/RunStateEventArgs.cs index 14c7eea938..9b77f7c91d 100644 --- a/Terminal.Gui/RunStateEventArgs.cs +++ b/Terminal.Gui/RunStateEventArgs.cs @@ -3,7 +3,7 @@ namespace Terminal.Gui { /// - /// Event arguments for events about + /// Event arguments for events about /// public class RunStateEventArgs : EventArgs { @@ -11,7 +11,7 @@ public class RunStateEventArgs : EventArgs { /// Creates a new instance of the class /// /// - public RunStateEventArgs (ApplicationRunState state) + public RunStateEventArgs (RunState state) { State = state; } @@ -19,6 +19,6 @@ public RunStateEventArgs (ApplicationRunState state) /// /// The state being reported on by the event /// - public ApplicationRunState State { get; } + public RunState State { get; } } } diff --git a/Terminal.Gui/Views/Toplevel.cs b/Terminal.Gui/Views/Toplevel.cs index c1ba0d0df9..d567f25786 100644 --- a/Terminal.Gui/Views/Toplevel.cs +++ b/Terminal.Gui/Views/Toplevel.cs @@ -31,9 +31,9 @@ public partial class Toplevel : View { public bool Running { get; set; } /// - /// Invoked when the has begun to be loaded. + /// Invoked when the has begun to be loaded. /// A Loaded event handler is a good place to finalize initialization before calling - /// . + /// . /// public event EventHandler Loaded; @@ -47,51 +47,51 @@ public partial class Toplevel : View { public event EventHandler Ready; /// - /// Invoked when the Toplevel has been unloaded. - /// A Unloaded event handler is a good place to dispose objects after calling . + /// Invoked when the Toplevel has been unloaded. + /// A Unloaded event handler is a good place to dispose objects after calling . /// public event EventHandler Unloaded; /// - /// Invoked when the Toplevel becomes the Toplevel. + /// Invoked when the Toplevel becomes the Toplevel. /// public event EventHandler Activate; /// - /// Invoked when the Toplevel ceases to be the Toplevel. + /// Invoked when the Toplevel ceases to be the Toplevel. /// public event EventHandler Deactivate; /// - /// Invoked when a child of the Toplevel is closed by - /// . + /// Invoked when a child of the Toplevel is closed by + /// . /// public event EventHandler ChildClosed; /// - /// Invoked when the last child of the Toplevel is closed from - /// by . + /// Invoked when the last child of the Toplevel is closed from + /// by . /// public event EventHandler AllChildClosed; /// - /// Invoked when the Toplevel's is being closed by + /// Invoked when the Toplevel's is being closed by /// . /// public event EventHandler Closing; /// - /// Invoked when the Toplevel's is closed by . + /// Invoked when the Toplevel's is closed by . /// public event EventHandler Closed; /// - /// Invoked when a child Toplevel's has been loaded. + /// Invoked when a child Toplevel's has been loaded. /// public event EventHandler ChildLoaded; /// - /// Invoked when a cjhild Toplevel's has been unloaded. + /// Invoked when a cjhild Toplevel's has been unloaded. /// public event EventHandler ChildUnloaded; @@ -174,7 +174,7 @@ internal virtual void OnReady () } /// - /// Called from before the is disposed. + /// Called from before the is disposed. /// internal virtual void OnUnloaded () { diff --git a/UICatalog/UICatalog.cs b/UICatalog/UICatalog.cs index aacd74b355..7e4bf420dc 100644 --- a/UICatalog/UICatalog.cs +++ b/UICatalog/UICatalog.cs @@ -839,10 +839,10 @@ static void VerifyObjectsWereDisposed () // Validate there are no outstanding Application.RunState-based instances // after a scenario was selected to run. This proves the main UI Catalog // 'app' closed cleanly. - foreach (var inst in ApplicationRunState.Instances) { + foreach (var inst in RunState.Instances) { Debug.Assert (inst.WasDisposed); } - ApplicationRunState.Instances.Clear (); + RunState.Instances.Clear (); #endif } diff --git a/UnitTests/Application/ApplicationTests.cs b/UnitTests/Application/ApplicationTests.cs index 1d2fe75792..e44534723e 100644 --- a/UnitTests/Application/ApplicationTests.cs +++ b/UnitTests/Application/ApplicationTests.cs @@ -15,7 +15,7 @@ public ApplicationTests () { #if DEBUG_IDISPOSABLE Responder.Instances.Clear (); - ApplicationRunState.Instances.Clear (); + RunState.Instances.Clear (); #endif } @@ -142,7 +142,7 @@ public void Init_Begin_End_Cleans_Up () Application.RequestStop (); }; - ApplicationRunState runstate = null; + RunState runstate = null; EventHandler NewRunStateFn = (s, e) => { Assert.NotNull (e.State); runstate = e.State; @@ -187,7 +187,7 @@ public void InitWithTopLevelFactory_Begin_End_Cleans_Up () Toplevel topLevel = null; Application.InternalInit (() => topLevel = new TestToplevel (), new FakeDriver ()); - ApplicationRunState runstate = null; + RunState runstate = null; EventHandler NewRunStateFn = (s, e) => { Assert.NotNull (e.State); runstate = e.State; diff --git a/UnitTests/Application/RunStateTests.cs b/UnitTests/Application/RunStateTests.cs index 72c02217d6..4592083606 100644 --- a/UnitTests/Application/RunStateTests.cs +++ b/UnitTests/Application/RunStateTests.cs @@ -18,25 +18,25 @@ public RunStateTests () { #if DEBUG_IDISPOSABLE Responder.Instances.Clear (); - ApplicationRunState.Instances.Clear (); + RunState.Instances.Clear (); #endif } [Fact] public void New_Creates_RunState () { - var rs = new ApplicationRunState (null); + var rs = new RunState (null); Assert.Null (rs.Toplevel); var top = new Toplevel (); - rs = new ApplicationRunState (top); + rs = new RunState (top); Assert.Equal (top, rs.Toplevel); } [Fact] public void Dispose_Cleans_Up_RunState () { - var rs = new ApplicationRunState (null); + var rs = new RunState (null); Assert.NotNull (rs); // Should not throw because Toplevel was null @@ -45,7 +45,7 @@ public void Dispose_Cleans_Up_RunState () Assert.True (rs.WasDisposed); #endif var top = new Toplevel (); - rs = new ApplicationRunState (top); + rs = new RunState (top); Assert.NotNull (rs); // Should throw because Toplevel was not cleaned up @@ -73,7 +73,7 @@ void Shutdown () Application.Shutdown (); #if DEBUG_IDISPOSABLE // Validate there are no outstanding RunState-based instances left - foreach (var inst in ApplicationRunState.Instances) Assert.True (inst.WasDisposed); + foreach (var inst in RunState.Instances) Assert.True (inst.WasDisposed); #endif } diff --git a/UnitTests/Dialogs/DialogTests.cs b/UnitTests/Dialogs/DialogTests.cs index 642d0edbe8..3adf9c1a96 100644 --- a/UnitTests/Dialogs/DialogTests.cs +++ b/UnitTests/Dialogs/DialogTests.cs @@ -42,7 +42,7 @@ public DialogTests (ITestOutputHelper output) // Application.End (runstate); //} - private (ApplicationRunState, Dialog) RunButtonTestDialog (string title, int width, Dialog.ButtonAlignments align, params Button [] btns) + private (RunState, Dialog) RunButtonTestDialog (string title, int width, Dialog.ButtonAlignments align, params Button [] btns) { var dlg = new Dialog (btns) { Title = title, @@ -209,7 +209,7 @@ public void Location_When_Not_Application_Top_Not_Default () public void ButtonAlignment_One () { var d = (FakeDriver)Application.Driver; - ApplicationRunState runstate = null; + RunState runstate = null; var title = "1234"; // E.g "|[ ok ]|" @@ -281,7 +281,7 @@ public void ButtonAlignment_One () [AutoInitShutdown] public void ButtonAlignment_Two () { - ApplicationRunState runstate = null; + RunState runstate = null; var d = (FakeDriver)Application.Driver; @@ -327,7 +327,7 @@ public void ButtonAlignment_Two () [AutoInitShutdown] public void ButtonAlignment_Two_Hidden () { - ApplicationRunState runstate = null; + RunState runstate = null; bool firstIteration = false; var d = (FakeDriver)Application.Driver; @@ -394,7 +394,7 @@ public void ButtonAlignment_Two_Hidden () [AutoInitShutdown] public void ButtonAlignment_Three () { - ApplicationRunState runstate = null; + RunState runstate = null; var d = (FakeDriver)Application.Driver; @@ -442,7 +442,7 @@ public void ButtonAlignment_Three () [AutoInitShutdown] public void ButtonAlignment_Four () { - ApplicationRunState runstate = null; + RunState runstate = null; var d = (FakeDriver)Application.Driver; @@ -493,7 +493,7 @@ public void ButtonAlignment_Four () [AutoInitShutdown] public void ButtonAlignment_Four_On_Too_Small_Width () { - ApplicationRunState runstate = null; + RunState runstate = null; var d = (FakeDriver)Application.Driver; @@ -540,7 +540,7 @@ public void ButtonAlignment_Four_On_Too_Small_Width () [AutoInitShutdown] public void ButtonAlignment_Four_Wider () { - ApplicationRunState runstate = null; + RunState runstate = null; var d = (FakeDriver)Application.Driver; @@ -594,7 +594,7 @@ public void ButtonAlignment_Four_Wider () [AutoInitShutdown] public void ButtonAlignment_Four_WideOdd () { - ApplicationRunState runstate = null; + RunState runstate = null; var d = (FakeDriver)Application.Driver; @@ -647,7 +647,7 @@ public void ButtonAlignment_Four_WideOdd () [AutoInitShutdown] public void Zero_Buttons_Works () { - ApplicationRunState runstate = null; + RunState runstate = null; var d = (FakeDriver)Application.Driver; @@ -667,7 +667,7 @@ public void Zero_Buttons_Works () [AutoInitShutdown] public void One_Button_Works () { - ApplicationRunState runstate = null; + RunState runstate = null; var d = (FakeDriver)Application.Driver; @@ -687,7 +687,7 @@ public void One_Button_Works () [AutoInitShutdown] public void Add_Button_Works () { - ApplicationRunState runstate = null; + RunState runstate = null; var d = (FakeDriver)Application.Driver; diff --git a/UnitTests/View/Layout/PosTests.cs b/UnitTests/View/Layout/PosTests.cs index 1f7ea4d6b0..3d92ff66fc 100644 --- a/UnitTests/View/Layout/PosTests.cs +++ b/UnitTests/View/Layout/PosTests.cs @@ -547,9 +547,9 @@ public void LeftTopBottomRight_Win_ShouldNotThrow () return (win, button); } - ApplicationRunState rs; + RunState rs; - void cleanup (ApplicationRunState rs) + void cleanup (RunState rs) { // Cleanup Application.End (rs); diff --git a/UnitTests/Views/OverlappedTests.cs b/UnitTests/Views/OverlappedTests.cs index bfc902ab29..e1f43d891f 100644 --- a/UnitTests/Views/OverlappedTests.cs +++ b/UnitTests/Views/OverlappedTests.cs @@ -15,7 +15,7 @@ public OverlappedTests () { #if DEBUG_IDISPOSABLE Responder.Instances.Clear (); - ApplicationRunState.Instances.Clear (); + RunState.Instances.Clear (); #endif } From f5de56845359fb98fe5e8c12d6df687ac5cc7d4b Mon Sep 17 00:00:00 2001 From: tznind Date: Tue, 23 May 2023 07:54:30 +0100 Subject: [PATCH 9/9] Switch to file scoped namespaces --- Terminal.Gui/Configuration/AppScope.cs | 59 ++- Terminal.Gui/Configuration/SettingsScope.cs | 185 +++++---- Terminal.Gui/Configuration/ThemeScope.cs | 95 +++-- Terminal.Gui/Timeout.cs | 23 +- Terminal.Gui/Views/GraphView/BarSeriesBar.cs | 64 ++- Terminal.Gui/Views/GraphView/LineF.cs | 40 +- Terminal.Gui/Views/Tab.cs | 61 ++- Terminal.Gui/Views/TabStyle.cs | 45 +- .../Views/TableView/CellColorGetterArgs.cs | 87 ++-- Terminal.Gui/Views/TableView/ColumnStyle.cs | 181 ++++----- .../Views/TableView/ListColumnStyle.cs | 29 +- .../Views/TableView/RowColorGetterArgs.cs | 35 +- .../Views/TableView/TableSelection.cs | 57 ++- Terminal.Gui/Views/TableView/TableStyle.cs | 257 ++++++------ Terminal.Gui/Views/Tile.cs | 149 ++++--- Terminal.Gui/Views/Wizard/WizardStep.cs | 383 +++++++++--------- 16 files changed, 866 insertions(+), 884 deletions(-) diff --git a/Terminal.Gui/Configuration/AppScope.cs b/Terminal.Gui/Configuration/AppScope.cs index 7d8586a4fa..1934063f82 100644 --- a/Terminal.Gui/Configuration/AppScope.cs +++ b/Terminal.Gui/Configuration/AppScope.cs @@ -9,35 +9,34 @@ #nullable enable -namespace Terminal.Gui { +namespace Terminal.Gui; - /// - /// The class for application-defined configuration settings. - /// - /// - /// - /// - /// - /// Use the attribute to mark properties that should be serialized as part - /// of application-defined configuration settings. - /// - /// - /// public class MyAppSettings { - /// [SerializableConfigurationProperty (Scope = typeof (AppScope))] - /// public static bool? MyProperty { get; set; } = true; - /// } - /// - /// - /// THe resultant Json will look like this: - /// - /// - /// "AppSettings": { - /// "MyAppSettings.MyProperty": true, - /// "UICatalog.ShowStatusBar": true - /// }, - /// - /// - [JsonConverter (typeof (ScopeJsonConverter))] - public class AppScope : Scope { - } +/// +/// The class for application-defined configuration settings. +/// +/// +/// +/// +/// +/// Use the attribute to mark properties that should be serialized as part +/// of application-defined configuration settings. +/// +/// +/// public class MyAppSettings { +/// [SerializableConfigurationProperty (Scope = typeof (AppScope))] +/// public static bool? MyProperty { get; set; } = true; +/// } +/// +/// +/// THe resultant Json will look like this: +/// +/// +/// "AppSettings": { +/// "MyAppSettings.MyProperty": true, +/// "UICatalog.ShowStatusBar": true +/// }, +/// +/// +[JsonConverter (typeof (ScopeJsonConverter))] +public class AppScope : Scope { } \ No newline at end of file diff --git a/Terminal.Gui/Configuration/SettingsScope.cs b/Terminal.Gui/Configuration/SettingsScope.cs index 857cf9e081..9618db1469 100644 --- a/Terminal.Gui/Configuration/SettingsScope.cs +++ b/Terminal.Gui/Configuration/SettingsScope.cs @@ -8,112 +8,111 @@ #nullable enable -namespace Terminal.Gui { +namespace Terminal.Gui; + +/// +/// The root object of Terminal.Gui configuration settings / JSON schema. Contains only properties +/// attributed with . +/// +/// +/// { +/// "$schema" : "https://gui-cs.github.io/Terminal.Gui/schemas/tui-config-schema.json", +/// "Application.UseSystemConsole" : true, +/// "Theme" : "Default", +/// "Themes": { +/// }, +/// }, +/// +/// +/// +[JsonConverter (typeof (ScopeJsonConverter))] +public class SettingsScope : Scope { /// - /// The root object of Terminal.Gui configuration settings / JSON schema. Contains only properties - /// attributed with . + /// Points to our JSON schema. /// - /// - /// { - /// "$schema" : "https://gui-cs.github.io/Terminal.Gui/schemas/tui-config-schema.json", - /// "Application.UseSystemConsole" : true, - /// "Theme" : "Default", - /// "Themes": { - /// }, - /// }, - /// - /// - /// - [JsonConverter (typeof (ScopeJsonConverter))] - public class SettingsScope : Scope { - /// - /// Points to our JSON schema. - /// - [JsonInclude, JsonPropertyName ("$schema")] - public string Schema { get; set; } = "https://gui-cs.github.io/Terminal.Gui/schemas/tui-config-schema.json"; + [JsonInclude, JsonPropertyName ("$schema")] + public string Schema { get; set; } = "https://gui-cs.github.io/Terminal.Gui/schemas/tui-config-schema.json"; - /// - /// The list of paths to the configuration files. - /// - public List Sources = new List (); + /// + /// The list of paths to the configuration files. + /// + public List Sources = new List (); - /// - /// Updates the with the settings in a JSON string. - /// - /// Json document to update the settings with. - /// The source (filename/resource name) the Json document was read from. - public SettingsScope? Update (Stream stream, string source) - { - // Update the existing settings with the new settings. - try { - Update (JsonSerializer.Deserialize (stream, ConfigurationManager._serializerOptions)!); - ConfigurationManager.OnUpdated (); - Debug.WriteLine ($"ConfigurationManager: Read configuration from \"{source}\""); - Sources.Add (source); - return this; - } catch (JsonException e) { - if (ConfigurationManager.ThrowOnJsonErrors ?? false) { - throw; - } else { - ConfigurationManager.AddJsonError ($"Error deserializing {source}: {e.Message}"); - } - } + /// + /// Updates the with the settings in a JSON string. + /// + /// Json document to update the settings with. + /// The source (filename/resource name) the Json document was read from. + public SettingsScope? Update (Stream stream, string source) + { + // Update the existing settings with the new settings. + try { + Update (JsonSerializer.Deserialize (stream, ConfigurationManager._serializerOptions)!); + ConfigurationManager.OnUpdated (); + Debug.WriteLine ($"ConfigurationManager: Read configuration from \"{source}\""); + Sources.Add (source); return this; - } - - /// - /// Updates the with the settings in a JSON file. - /// - /// - public SettingsScope? Update (string filePath) - { - var realPath = filePath.Replace ("~", Environment.GetFolderPath (Environment.SpecialFolder.UserProfile)); - if (!File.Exists (realPath)) { - Debug.WriteLine ($"ConfigurationManager: Configuration file \"{realPath}\" does not exist."); - Sources.Add (filePath); - return this; + } catch (JsonException e) { + if (ConfigurationManager.ThrowOnJsonErrors ?? false) { + throw; + } else { + ConfigurationManager.AddJsonError ($"Error deserializing {source}: {e.Message}"); } - - var stream = File.OpenRead (realPath); - return Update (stream, filePath); } + return this; + } - /// - /// Updates the with the settings from a Json resource. - /// - /// - /// - public SettingsScope? UpdateFromResource (Assembly assembly, string resourceName) - { - if (resourceName == null || string.IsNullOrEmpty (resourceName)) { - Debug.WriteLine ($"ConfigurationManager: Resource \"{resourceName}\" does not exist in \"{assembly.GetName ().Name}\"."); - return this; - } + /// + /// Updates the with the settings in a JSON file. + /// + /// + public SettingsScope? Update (string filePath) + { + var realPath = filePath.Replace ("~", Environment.GetFolderPath (Environment.SpecialFolder.UserProfile)); + if (!File.Exists (realPath)) { + Debug.WriteLine ($"ConfigurationManager: Configuration file \"{realPath}\" does not exist."); + Sources.Add (filePath); + return this; + } - using Stream? stream = assembly.GetManifestResourceStream (resourceName)!; - if (stream == null) { - Debug.WriteLine ($"ConfigurationManager: Failed to read resource \"{resourceName}\" from \"{assembly.GetName ().Name}\"."); - return this; - } + var stream = File.OpenRead (realPath); + return Update (stream, filePath); + } - return Update (stream, $"resource://[{assembly.GetName ().Name}]/{resourceName}"); + /// + /// Updates the with the settings from a Json resource. + /// + /// + /// + public SettingsScope? UpdateFromResource (Assembly assembly, string resourceName) + { + if (resourceName == null || string.IsNullOrEmpty (resourceName)) { + Debug.WriteLine ($"ConfigurationManager: Resource \"{resourceName}\" does not exist in \"{assembly.GetName ().Name}\"."); + return this; } - /// - /// Updates the with the settings in a JSON string. - /// - /// Json document to update the settings with. - /// The source (filename/resource name) the Json document was read from. - public SettingsScope? Update (string json, string source) - { - var stream = new MemoryStream (); - var writer = new StreamWriter (stream); - writer.Write (json); - writer.Flush (); - stream.Position = 0; - - return Update (stream, source); + using Stream? stream = assembly.GetManifestResourceStream (resourceName)!; + if (stream == null) { + Debug.WriteLine ($"ConfigurationManager: Failed to read resource \"{resourceName}\" from \"{assembly.GetName ().Name}\"."); + return this; } + + return Update (stream, $"resource://[{assembly.GetName ().Name}]/{resourceName}"); } + /// + /// Updates the with the settings in a JSON string. + /// + /// Json document to update the settings with. + /// The source (filename/resource name) the Json document was read from. + public SettingsScope? Update (string json, string source) + { + var stream = new MemoryStream (); + var writer = new StreamWriter (stream); + writer.Write (json); + writer.Flush (); + stream.Position = 0; + + return Update (stream, source); + } } diff --git a/Terminal.Gui/Configuration/ThemeScope.cs b/Terminal.Gui/Configuration/ThemeScope.cs index e9da8fa0ae..924388392e 100644 --- a/Terminal.Gui/Configuration/ThemeScope.cs +++ b/Terminal.Gui/Configuration/ThemeScope.cs @@ -2,55 +2,54 @@ #nullable enable -namespace Terminal.Gui { +namespace Terminal.Gui; - /// - /// The root object for a Theme. A Theme is a set of settings that are applied to the running - /// as a group. - /// - /// - /// - /// - /// - /// - /// "Default": { - /// "ColorSchemes": [ - /// { - /// "TopLevel": { - /// "Normal": { - /// "Foreground": "BrightGreen", - /// "Background": "Black" - /// }, - /// "Focus": { - /// "Foreground": "White", - /// "Background": "Cyan" - /// - /// }, - /// "HotNormal": { - /// "Foreground": "Brown", - /// "Background": "Black" - /// - /// }, - /// "HotFocus": { - /// "Foreground": "Blue", - /// "Background": "Cyan" - /// }, - /// "Disabled": { - /// "Foreground": "DarkGray", - /// "Background": "Black" - /// - /// } - /// } - /// - [JsonConverter (typeof (ScopeJsonConverter))] - public class ThemeScope : Scope { +/// +/// The root object for a Theme. A Theme is a set of settings that are applied to the running +/// as a group. +/// +/// +/// +/// +/// +/// +/// "Default": { +/// "ColorSchemes": [ +/// { +/// "TopLevel": { +/// "Normal": { +/// "Foreground": "BrightGreen", +/// "Background": "Black" +/// }, +/// "Focus": { +/// "Foreground": "White", +/// "Background": "Cyan" +/// +/// }, +/// "HotNormal": { +/// "Foreground": "Brown", +/// "Background": "Black" +/// +/// }, +/// "HotFocus": { +/// "Foreground": "Blue", +/// "Background": "Cyan" +/// }, +/// "Disabled": { +/// "Foreground": "DarkGray", +/// "Background": "Black" +/// +/// } +/// } +/// +[JsonConverter (typeof (ScopeJsonConverter))] +public class ThemeScope : Scope { - /// - internal override bool Apply () - { - var ret = base.Apply (); - Application.Driver?.InitalizeColorSchemes (); - return ret; - } + /// + internal override bool Apply () + { + var ret = base.Apply (); + Application.Driver?.InitalizeColorSchemes (); + return ret; } } \ No newline at end of file diff --git a/Terminal.Gui/Timeout.cs b/Terminal.Gui/Timeout.cs index 643aa3ba99..4273e034ae 100644 --- a/Terminal.Gui/Timeout.cs +++ b/Terminal.Gui/Timeout.cs @@ -6,19 +6,18 @@ // using System; -namespace Terminal.Gui { +namespace Terminal.Gui; +/// +/// Provides data for timers running manipulation. +/// +public sealed class Timeout { /// - /// Provides data for timers running manipulation. + /// Time to wait before invoke the callback. /// - public sealed class Timeout { - /// - /// Time to wait before invoke the callback. - /// - public TimeSpan Span; - /// - /// The function that will be invoked. - /// - public Func Callback; - } + public TimeSpan Span; + /// + /// The function that will be invoked. + /// + public Func Callback; } diff --git a/Terminal.Gui/Views/GraphView/BarSeriesBar.cs b/Terminal.Gui/Views/GraphView/BarSeriesBar.cs index 3f3df31a25..41fa65852a 100644 --- a/Terminal.Gui/Views/GraphView/BarSeriesBar.cs +++ b/Terminal.Gui/Views/GraphView/BarSeriesBar.cs @@ -1,40 +1,38 @@ -namespace Terminal.Gui { +namespace Terminal.Gui; + +/// +/// A single bar in a +/// +public class BarSeriesBar { /// - /// A single bar in a + /// Optional text that describes the bar. This will be rendered on the corresponding + /// unless is false /// - public class BarSeriesBar { - - /// - /// Optional text that describes the bar. This will be rendered on the corresponding - /// unless is false - /// - public string Text { get; set; } + public string Text { get; set; } - /// - /// The color and character that will be rendered in the console - /// when the bar extends over it - /// - public GraphCellToRender Fill { get; set; } + /// + /// The color and character that will be rendered in the console + /// when the bar extends over it + /// + public GraphCellToRender Fill { get; set; } - /// - /// The value in graph space X/Y (depending on ) to which the bar extends. - /// - public float Value { get; } + /// + /// The value in graph space X/Y (depending on ) to which the bar extends. + /// + public float Value { get; } - /// - /// Creates a new instance of a single bar rendered in the given that extends - /// out graph space units in the default - /// - /// - /// - /// - public BarSeriesBar (string text, GraphCellToRender fill, float value) - { - Text = text; - Fill = fill; - Value = value; - } + /// + /// Creates a new instance of a single bar rendered in the given that extends + /// out graph space units in the default + /// + /// + /// + /// + public BarSeriesBar (string text, GraphCellToRender fill, float value) + { + Text = text; + Fill = fill; + Value = value; } - -} \ No newline at end of file +} diff --git a/Terminal.Gui/Views/GraphView/LineF.cs b/Terminal.Gui/Views/GraphView/LineF.cs index 623c6dbbc7..30eb03c548 100644 --- a/Terminal.Gui/Views/GraphView/LineF.cs +++ b/Terminal.Gui/Views/GraphView/LineF.cs @@ -1,27 +1,25 @@ -namespace Terminal.Gui { +namespace Terminal.Gui; +/// +/// Describes two points in graph space and a line between them +/// +public class LineF { /// - /// Describes two points in graph space and a line between them + /// The start of the line /// - public class LineF { - /// - /// The start of the line - /// - public PointF Start { get; } + public PointF Start { get; } - /// - /// The end point of the line - /// - public PointF End { get; } + /// + /// The end point of the line + /// + public PointF End { get; } - /// - /// Creates a new line between the points - /// - public LineF (PointF start, PointF end) - { - this.Start = start; - this.End = end; - } + /// + /// Creates a new line between the points + /// + public LineF (PointF start, PointF end) + { + this.Start = start; + this.End = end; } - -} \ No newline at end of file +} diff --git a/Terminal.Gui/Views/Tab.cs b/Terminal.Gui/Views/Tab.cs index de9a3da8fc..0c0be4a2cd 100644 --- a/Terminal.Gui/Views/Tab.cs +++ b/Terminal.Gui/Views/Tab.cs @@ -1,40 +1,39 @@ -namespace Terminal.Gui { +namespace Terminal.Gui; + +/// +/// A single tab in a +/// +public class Tab { + private string text; /// - /// A single tab in a + /// The text to display in a /// - public class Tab { - private string text; - - /// - /// The text to display in a - /// - /// - public string Text { get => text ?? "Unamed"; set => text = value; } + /// + public string Text { get => text ?? "Unamed"; set => text = value; } - /// - /// The control to display when the tab is selected - /// - /// - public View View { get; set; } + /// + /// The control to display when the tab is selected + /// + /// + public View View { get; set; } - /// - /// Creates a new unamed tab with no controls inside - /// - public Tab () - { + /// + /// Creates a new unamed tab with no controls inside + /// + public Tab () + { - } + } - /// - /// Creates a new tab with the given text hosting a view - /// - /// - /// - public Tab (string text, View view) - { - this.Text = text; - this.View = view; - } + /// + /// Creates a new tab with the given text hosting a view + /// + /// + /// + public Tab (string text, View view) + { + this.Text = text; + this.View = view; } } diff --git a/Terminal.Gui/Views/TabStyle.cs b/Terminal.Gui/Views/TabStyle.cs index b1c75960e8..b589cac72e 100644 --- a/Terminal.Gui/Views/TabStyle.cs +++ b/Terminal.Gui/Views/TabStyle.cs @@ -1,29 +1,28 @@ -namespace Terminal.Gui { +namespace Terminal.Gui; - /// - /// Describes render stylistic selections of a - /// - public class TabStyle { +/// +/// Describes render stylistic selections of a +/// +public class TabStyle { - /// - /// True to show the top lip of tabs. False to directly begin with tab text during - /// rendering. When true header line occupies 3 rows, when false only 2. - /// Defaults to true. - /// - /// When is enabled this instead applies to the - /// bottommost line of the control - /// - public bool ShowTopLine { get; set; } = true; + /// + /// True to show the top lip of tabs. False to directly begin with tab text during + /// rendering. When true header line occupies 3 rows, when false only 2. + /// Defaults to true. + /// + /// When is enabled this instead applies to the + /// bottommost line of the control + /// + public bool ShowTopLine { get; set; } = true; - /// - /// True to show a solid box around the edge of the control. Defaults to true. - /// - public bool ShowBorder { get; set; } = true; + /// + /// True to show a solid box around the edge of the control. Defaults to true. + /// + public bool ShowBorder { get; set; } = true; - /// - /// True to render tabs at the bottom of the view instead of the top - /// - public bool TabsOnBottom { get; set; } = false; + /// + /// True to render tabs at the bottom of the view instead of the top + /// + public bool TabsOnBottom { get; set; } = false; - } } diff --git a/Terminal.Gui/Views/TableView/CellColorGetterArgs.cs b/Terminal.Gui/Views/TableView/CellColorGetterArgs.cs index 50d97716a8..31ceb1e51e 100644 --- a/Terminal.Gui/Views/TableView/CellColorGetterArgs.cs +++ b/Terminal.Gui/Views/TableView/CellColorGetterArgs.cs @@ -1,50 +1,49 @@ -namespace Terminal.Gui { +namespace Terminal.Gui; + +/// +/// Arguments for a . Describes a cell for which a rendering +/// is being sought +/// +public class CellColorGetterArgs { + + /// + /// The data table hosted by the control. + /// + public ITableSource Table { get; } + + /// + /// The index of the row in for which color is needed + /// + public int RowIndex { get; } + + /// + /// The index of column in for which color is needed + /// + public int ColIdex { get; } + + /// + /// The hard typed value being rendered in the cell for which color is needed + /// + public object CellValue { get; } /// - /// Arguments for a . Describes a cell for which a rendering - /// is being sought + /// The textual representation of (what will actually be drawn to the screen) /// - public class CellColorGetterArgs { - - /// - /// The data table hosted by the control. - /// - public ITableSource Table { get; } - - /// - /// The index of the row in for which color is needed - /// - public int RowIndex { get; } - - /// - /// The index of column in for which color is needed - /// - public int ColIdex { get; } - - /// - /// The hard typed value being rendered in the cell for which color is needed - /// - public object CellValue { get; } - - /// - /// The textual representation of (what will actually be drawn to the screen) - /// - public string Representation { get; } - - /// - /// the color scheme that is going to be used to render the cell if no cell specific color scheme is returned - /// - public ColorScheme RowScheme { get; } - - internal CellColorGetterArgs (ITableSource table, int rowIdx, int colIdx, object cellValue, string representation, ColorScheme rowScheme) - { - Table = table; - RowIndex = rowIdx; - ColIdex = colIdx; - CellValue = cellValue; - Representation = representation; - RowScheme = rowScheme; - } + public string Representation { get; } + /// + /// the color scheme that is going to be used to render the cell if no cell specific color scheme is returned + /// + public ColorScheme RowScheme { get; } + + internal CellColorGetterArgs (ITableSource table, int rowIdx, int colIdx, object cellValue, string representation, ColorScheme rowScheme) + { + Table = table; + RowIndex = rowIdx; + ColIdex = colIdx; + CellValue = cellValue; + Representation = representation; + RowScheme = rowScheme; } + } \ No newline at end of file diff --git a/Terminal.Gui/Views/TableView/ColumnStyle.cs b/Terminal.Gui/Views/TableView/ColumnStyle.cs index a55d5f7042..b7a57f0da5 100644 --- a/Terminal.Gui/Views/TableView/ColumnStyle.cs +++ b/Terminal.Gui/Views/TableView/ColumnStyle.cs @@ -1,104 +1,103 @@ using System; -namespace Terminal.Gui { +namespace Terminal.Gui; + +/// +/// Describes how to render a given column in a including +/// and textual representation of cells (e.g. date formats) +/// +/// See TableView Deep Dive for more information. +/// +public class ColumnStyle { + + /// + /// Defines the default alignment for all values rendered in this column. For custom alignment based on cell contents use . + /// + public TextAlignment Alignment { get; set; } + + /// + /// Defines a delegate for returning custom alignment per cell based on cell values. When specified this will override + /// + public Func AlignmentGetter; + + /// + /// Defines a delegate for returning custom representations of cell values. If not set then is used. Return values from your delegate may be truncated e.g. based on + /// + public Func RepresentationGetter; + + /// + /// Defines a delegate for returning a custom color scheme per cell based on cell values. + /// Return null for the default + /// + public CellColorGetterDelegate ColorGetter; + private bool visible = true; + + /// + /// Defines the format for values e.g. "yyyy-MM-dd" for dates + /// + public string Format { get; set; } /// - /// Describes how to render a given column in a including - /// and textual representation of cells (e.g. date formats) + /// Set the maximum width of the column in characters. This value will be ignored if more than the tables . Defaults to + /// + public int MaxWidth { get; set; } = TableView.DefaultMaxCellWidth; + + /// + /// Set the minimum width of the column in characters. Setting this will ensure that + /// even when a column has short content/header it still fills a given width of the control. /// - /// See TableView Deep Dive for more information. + /// This value will be ignored if more than the tables + /// or the + /// + /// + /// For setting a flexible column width (down to a lower limit) use + /// instead + /// /// - public class ColumnStyle { - - /// - /// Defines the default alignment for all values rendered in this column. For custom alignment based on cell contents use . - /// - public TextAlignment Alignment { get; set; } - - /// - /// Defines a delegate for returning custom alignment per cell based on cell values. When specified this will override - /// - public Func AlignmentGetter; - - /// - /// Defines a delegate for returning custom representations of cell values. If not set then is used. Return values from your delegate may be truncated e.g. based on - /// - public Func RepresentationGetter; - - /// - /// Defines a delegate for returning a custom color scheme per cell based on cell values. - /// Return null for the default - /// - public CellColorGetterDelegate ColorGetter; - private bool visible = true; - - /// - /// Defines the format for values e.g. "yyyy-MM-dd" for dates - /// - public string Format { get; set; } - - /// - /// Set the maximum width of the column in characters. This value will be ignored if more than the tables . Defaults to - /// - public int MaxWidth { get; set; } = TableView.DefaultMaxCellWidth; - - /// - /// Set the minimum width of the column in characters. Setting this will ensure that - /// even when a column has short content/header it still fills a given width of the control. - /// - /// This value will be ignored if more than the tables - /// or the - /// - /// - /// For setting a flexible column width (down to a lower limit) use - /// instead - /// - /// - public int MinWidth { get; set; } - - /// - /// Enables flexible sizing of this column based on available screen space to render into. - /// - public int MinAcceptableWidth { get; set; } = TableView.DefaultMinAcceptableWidth; - - /// - /// Gets or Sets a value indicating whether the column should be visible to the user. - /// This affects both whether it is rendered and whether it can be selected. Defaults to - /// true. - /// - /// If is 0 then will always return false. - public bool Visible { get => MaxWidth >= 0 && visible; set => visible = value; } - - /// - /// Returns the alignment for the cell based on and / - /// - /// - /// - public TextAlignment GetAlignment (object cellValue) - { - if (AlignmentGetter != null) - return AlignmentGetter (cellValue); - - return Alignment; - } + public int MinWidth { get; set; } - /// - /// Returns the full string to render (which may be truncated if too long) that the current style says best represents the given - /// - /// - /// - public string GetRepresentation (object value) - { - if (!string.IsNullOrWhiteSpace (Format)) { + /// + /// Enables flexible sizing of this column based on available screen space to render into. + /// + public int MinAcceptableWidth { get; set; } = TableView.DefaultMinAcceptableWidth; - if (value is IFormattable f) - return f.ToString (Format, null); - } + /// + /// Gets or Sets a value indicating whether the column should be visible to the user. + /// This affects both whether it is rendered and whether it can be selected. Defaults to + /// true. + /// + /// If is 0 then will always return false. + public bool Visible { get => MaxWidth >= 0 && visible; set => visible = value; } - if (RepresentationGetter != null) - return RepresentationGetter (value); + /// + /// Returns the alignment for the cell based on and / + /// + /// + /// + public TextAlignment GetAlignment (object cellValue) + { + if (AlignmentGetter != null) + return AlignmentGetter (cellValue); + + return Alignment; + } - return value?.ToString (); + /// + /// Returns the full string to render (which may be truncated if too long) that the current style says best represents the given + /// + /// + /// + public string GetRepresentation (object value) + { + if (!string.IsNullOrWhiteSpace (Format)) { + + if (value is IFormattable f) + return f.ToString (Format, null); } + + if (RepresentationGetter != null) + return RepresentationGetter (value); + + return value?.ToString (); } } \ No newline at end of file diff --git a/Terminal.Gui/Views/TableView/ListColumnStyle.cs b/Terminal.Gui/Views/TableView/ListColumnStyle.cs index 3bf5b55856..338501ec5f 100644 --- a/Terminal.Gui/Views/TableView/ListColumnStyle.cs +++ b/Terminal.Gui/Views/TableView/ListColumnStyle.cs @@ -1,19 +1,18 @@ -namespace Terminal.Gui { +namespace Terminal.Gui; +/// +/// Defines rendering options that affect how the view is displayed. +/// +public class ListColumnStyle { + /// - /// Defines rendering options that affect how the view is displayed. + /// Gets or sets an Orientation enum indicating whether to populate data down each column + /// rather than across each row. Defaults to . /// - public class ListColumnStyle { - - /// - /// Gets or sets an Orientation enum indicating whether to populate data down each column - /// rather than across each row. Defaults to . - /// - public Orientation Orientation { get; set; } = Orientation.Horizontal; + public Orientation Orientation { get; set; } = Orientation.Horizontal; - /// - /// Gets or sets a flag indicating whether to scroll in the same direction as . - /// Defaults to . - /// - public bool ScrollParallel { get; set; } = false; - } + /// + /// Gets or sets a flag indicating whether to scroll in the same direction as . + /// Defaults to . + /// + public bool ScrollParallel { get; set; } = false; } diff --git a/Terminal.Gui/Views/TableView/RowColorGetterArgs.cs b/Terminal.Gui/Views/TableView/RowColorGetterArgs.cs index 220d8fdeb2..ccb5ea0928 100644 --- a/Terminal.Gui/Views/TableView/RowColorGetterArgs.cs +++ b/Terminal.Gui/Views/TableView/RowColorGetterArgs.cs @@ -1,25 +1,24 @@ -namespace Terminal.Gui { +namespace Terminal.Gui; + +/// +/// Arguments for . Describes a row of data in a +/// for which is sought. +/// +public class RowColorGetterArgs { /// - /// Arguments for . Describes a row of data in a - /// for which is sought. + /// The data table hosted by the control. /// - public class RowColorGetterArgs { - - /// - /// The data table hosted by the control. - /// - public ITableSource Table { get; } + public ITableSource Table { get; } - /// - /// The index of the row in for which color is needed - /// - public int RowIndex { get; } + /// + /// The index of the row in for which color is needed + /// + public int RowIndex { get; } - internal RowColorGetterArgs (ITableSource table, int rowIdx) - { - Table = table; - RowIndex = rowIdx; - } + internal RowColorGetterArgs (ITableSource table, int rowIdx) + { + Table = table; + RowIndex = rowIdx; } } \ No newline at end of file diff --git a/Terminal.Gui/Views/TableView/TableSelection.cs b/Terminal.Gui/Views/TableView/TableSelection.cs index 89a2290bd1..35249e03b9 100644 --- a/Terminal.Gui/Views/TableView/TableSelection.cs +++ b/Terminal.Gui/Views/TableView/TableSelection.cs @@ -1,37 +1,36 @@ -namespace Terminal.Gui { +namespace Terminal.Gui; + +/// +/// Describes a selected region of the table +/// +public class TableSelection { /// - /// Describes a selected region of the table + /// Corner of the where selection began /// - public class TableSelection { - - /// - /// Corner of the where selection began - /// - /// - public Point Origin { get; set; } + /// + public Point Origin { get; set; } - /// - /// Area selected - /// - /// - public Rect Rect { get; set; } + /// + /// Area selected + /// + /// + public Rect Rect { get; set; } - /// - /// True if the selection was made through - /// and therefore should persist even through keyboard navigation. - /// - public bool IsToggled { get; set; } + /// + /// True if the selection was made through + /// and therefore should persist even through keyboard navigation. + /// + public bool IsToggled { get; set; } - /// - /// Creates a new selected area starting at the origin corner and covering the provided rectangular area - /// - /// - /// - public TableSelection (Point origin, Rect rect) - { - Origin = origin; - Rect = rect; - } + /// + /// Creates a new selected area starting at the origin corner and covering the provided rectangular area + /// + /// + /// + public TableSelection (Point origin, Rect rect) + { + Origin = origin; + Rect = rect; } } \ No newline at end of file diff --git a/Terminal.Gui/Views/TableView/TableStyle.cs b/Terminal.Gui/Views/TableView/TableStyle.cs index 98cf313007..d0bb1eb155 100644 --- a/Terminal.Gui/Views/TableView/TableStyle.cs +++ b/Terminal.Gui/Views/TableView/TableStyle.cs @@ -1,133 +1,132 @@ using System.Collections.Generic; -namespace Terminal.Gui { - - /// - /// Defines rendering options that affect how the table is displayed. - /// - /// See TableView Deep Dive for more information. - /// - public class TableStyle { - - /// - /// Gets or sets a flag indicating whether to render headers of a . - /// Defaults to . - /// - /// , etc - /// may still be used even if is . - public bool ShowHeaders { get; set; } = true; - - /// - /// When scrolling down always lock the column headers in place as the first row of the table - /// - public bool AlwaysShowHeaders { get; set; } = false; - - /// - /// True to render a solid line above the headers - /// - public bool ShowHorizontalHeaderOverline { get; set; } = true; - - /// - /// True to render a solid line under the headers - /// - public bool ShowHorizontalHeaderUnderline { get; set; } = true; - - /// - /// True to render a solid line vertical line between cells - /// - public bool ShowVerticalCellLines { get; set; } = true; - - /// - /// True to render a solid line vertical line between headers - /// - public bool ShowVerticalHeaderLines { get; set; } = true; - - /// - /// True to render a arrows on the right/left of the table when - /// there are more column(s) that can be scrolled to. Requires - /// to be true. - /// Defaults to true - /// - public bool ShowHorizontalScrollIndicators { get; set; } = true; - - - /// - /// Gets or sets a flag indicating whether there should be a horizontal line after all the data - /// in the table. Defaults to . - /// - public bool ShowHorizontalBottomline { get; set; } = false; - - /// - /// True to invert the colors of the first symbol of the selected cell in the . - /// This gives the appearance of a cursor for when the doesn't otherwise show - /// this - /// - public bool InvertSelectedCellFirstCharacter { get; set; } = false; - - /// - /// Gets or sets a flag indicating whether to force use when rendering - /// vertical cell lines (even when is on). - /// - public bool AlwaysUseNormalColorForVerticalCellLines { get; set; } = false; - - /// - /// Collection of columns for which you want special rendering (e.g. custom column lengths, text alignment etc) - /// - public Dictionary ColumnStyles { get; set; } = new Dictionary (); - - /// - /// Delegate for coloring specific rows in a different color. For cell color - /// - /// - public RowColorGetterDelegate RowColorGetter { get; set; } - - /// - /// Determines rendering when the last column in the table is visible but it's - /// content or is less than the remaining - /// space in the control. True (the default) will expand the column to fill - /// the remaining bounds of the control. False will draw a column ending line - /// and leave a blank column that cannot be selected in the remaining space. - /// - /// - public bool ExpandLastColumn { get; set; } = true; - - /// - /// - /// Determines how is updated when scrolling - /// right off the end of the currently visible area. - /// - /// - /// If true then when scrolling right the scroll offset is increased the minimum required to show - /// the new column. This may be slow if you have an incredibly large number of columns in - /// your table and/or slow implementations - /// - /// - /// If false then scroll offset is set to the currently selected column (i.e. PageRight). - /// - /// - public bool SmoothHorizontalScrolling { get; set; } = true; - - /// - /// Returns the entry from for the given or null if no custom styling is defined for it - /// - /// - /// - public ColumnStyle GetColumnStyleIfAny (int col) - { - return ColumnStyles.TryGetValue (col, out ColumnStyle result) ? result : null; - } - - /// - /// Returns an existing for the given or creates a new one with default options - /// - /// - /// - public ColumnStyle GetOrCreateColumnStyle (int col) - { - if (!ColumnStyles.ContainsKey (col)) - ColumnStyles.Add (col, new ColumnStyle ()); - - return ColumnStyles [col]; - } +namespace Terminal.Gui; + +/// +/// Defines rendering options that affect how the table is displayed. +/// +/// See TableView Deep Dive for more information. +/// +public class TableStyle { + + /// + /// Gets or sets a flag indicating whether to render headers of a . + /// Defaults to . + /// + /// , etc + /// may still be used even if is . + public bool ShowHeaders { get; set; } = true; + + /// + /// When scrolling down always lock the column headers in place as the first row of the table + /// + public bool AlwaysShowHeaders { get; set; } = false; + + /// + /// True to render a solid line above the headers + /// + public bool ShowHorizontalHeaderOverline { get; set; } = true; + + /// + /// True to render a solid line under the headers + /// + public bool ShowHorizontalHeaderUnderline { get; set; } = true; + + /// + /// True to render a solid line vertical line between cells + /// + public bool ShowVerticalCellLines { get; set; } = true; + + /// + /// True to render a solid line vertical line between headers + /// + public bool ShowVerticalHeaderLines { get; set; } = true; + + /// + /// True to render a arrows on the right/left of the table when + /// there are more column(s) that can be scrolled to. Requires + /// to be true. + /// Defaults to true + /// + public bool ShowHorizontalScrollIndicators { get; set; } = true; + + + /// + /// Gets or sets a flag indicating whether there should be a horizontal line after all the data + /// in the table. Defaults to . + /// + public bool ShowHorizontalBottomline { get; set; } = false; + + /// + /// True to invert the colors of the first symbol of the selected cell in the . + /// This gives the appearance of a cursor for when the doesn't otherwise show + /// this + /// + public bool InvertSelectedCellFirstCharacter { get; set; } = false; + + /// + /// Gets or sets a flag indicating whether to force use when rendering + /// vertical cell lines (even when is on). + /// + public bool AlwaysUseNormalColorForVerticalCellLines { get; set; } = false; + + /// + /// Collection of columns for which you want special rendering (e.g. custom column lengths, text alignment etc) + /// + public Dictionary ColumnStyles { get; set; } = new Dictionary (); + + /// + /// Delegate for coloring specific rows in a different color. For cell color + /// + /// + public RowColorGetterDelegate RowColorGetter { get; set; } + + /// + /// Determines rendering when the last column in the table is visible but it's + /// content or is less than the remaining + /// space in the control. True (the default) will expand the column to fill + /// the remaining bounds of the control. False will draw a column ending line + /// and leave a blank column that cannot be selected in the remaining space. + /// + /// + public bool ExpandLastColumn { get; set; } = true; + + /// + /// + /// Determines how is updated when scrolling + /// right off the end of the currently visible area. + /// + /// + /// If true then when scrolling right the scroll offset is increased the minimum required to show + /// the new column. This may be slow if you have an incredibly large number of columns in + /// your table and/or slow implementations + /// + /// + /// If false then scroll offset is set to the currently selected column (i.e. PageRight). + /// + /// + public bool SmoothHorizontalScrolling { get; set; } = true; + + /// + /// Returns the entry from for the given or null if no custom styling is defined for it + /// + /// + /// + public ColumnStyle GetColumnStyleIfAny (int col) + { + return ColumnStyles.TryGetValue (col, out ColumnStyle result) ? result : null; + } + + /// + /// Returns an existing for the given or creates a new one with default options + /// + /// + /// + public ColumnStyle GetOrCreateColumnStyle (int col) + { + if (!ColumnStyles.ContainsKey (col)) + ColumnStyles.Add (col, new ColumnStyle ()); + + return ColumnStyles [col]; } } \ No newline at end of file diff --git a/Terminal.Gui/Views/Tile.cs b/Terminal.Gui/Views/Tile.cs index 34a8caf01f..8e626da3a7 100644 --- a/Terminal.Gui/Views/Tile.cs +++ b/Terminal.Gui/Views/Tile.cs @@ -1,95 +1,94 @@ using System; -namespace Terminal.Gui { +namespace Terminal.Gui; +/// +/// A single presented in a . To create +/// new instances use +/// or . +/// +public class Tile { /// - /// A single presented in a . To create - /// new instances use - /// or . + /// The that is contained in this . + /// Add new child views to this member for multiple + /// s within the . /// - public class Tile { - /// - /// The that is contained in this . - /// Add new child views to this member for multiple - /// s within the . - /// - public View ContentView { get; internal set; } + public View ContentView { get; internal set; } - /// - /// Gets or Sets the minimum size you to allow when splitter resizing along - /// parent direction. - /// - public int MinSize { get; set; } + /// + /// Gets or Sets the minimum size you to allow when splitter resizing along + /// parent direction. + /// + public int MinSize { get; set; } - /// - /// The text that should be displayed above the . This - /// will appear over the splitter line or border (above the view client area). - /// - /// - /// Title are not rendered for root level tiles - /// is . - /// - public string Title { - get => _title; - set { - if (!OnTitleChanging (_title, value)) { - var old = _title; - _title = value; - OnTitleChanged (old, _title); - return; - } + /// + /// The text that should be displayed above the . This + /// will appear over the splitter line or border (above the view client area). + /// + /// + /// Title are not rendered for root level tiles + /// is . + /// + public string Title { + get => _title; + set { + if (!OnTitleChanging (_title, value)) { + var old = _title; _title = value; + OnTitleChanged (old, _title); + return; } + _title = value; } + } - private string _title = string.Empty; + private string _title = string.Empty; - /// - /// 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 cancelled the Title change. - public virtual bool OnTitleChanging (string oldTitle, string newTitle) - { - var args = new TitleEventArgs (oldTitle, newTitle); - TitleChanging?.Invoke (this, args); - return args.Cancel; - } + /// + /// 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 cancelled the Title change. + public virtual bool OnTitleChanging (string oldTitle, string newTitle) + { + var args = new TitleEventArgs (oldTitle, newTitle); + TitleChanging?.Invoke (this, args); + return args.Cancel; + } - /// - /// Event fired when the is changing. Set to - /// true to cancel the Title change. - /// - public event EventHandler TitleChanging; + /// + /// Event fired when the is changing. Set to + /// true to cancel the Title change. + /// + public event EventHandler 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 (string oldTitle, string newTitle) - { - var args = new TitleEventArgs (oldTitle, newTitle); - TitleChanged?.Invoke (this, args); - } + /// + /// Called when the has been changed. Invokes the event. + /// + /// The that is/has been replaced. + /// The new to be replaced. + public virtual void OnTitleChanged (string oldTitle, string newTitle) + { + var args = new TitleEventArgs (oldTitle, newTitle); + TitleChanged?.Invoke (this, args); + } - /// - /// Event fired after the has been changed. - /// - public event EventHandler TitleChanged; + /// + /// Event fired after the has been changed. + /// + public event EventHandler TitleChanged; - /// - /// Creates a new instance of the class. - /// - public Tile () - { - ContentView = new View () { Width = Dim.Fill (), Height = Dim.Fill () }; + /// + /// Creates a new instance of the class. + /// + public Tile () + { + ContentView = new View () { Width = Dim.Fill (), Height = Dim.Fill () }; #if DEBUG_IDISPOSABLE - ContentView.Data = "Tile.ContentView"; + ContentView.Data = "Tile.ContentView"; #endif - Title = string.Empty; - MinSize = 0; - } + Title = string.Empty; + MinSize = 0; } } diff --git a/Terminal.Gui/Views/Wizard/WizardStep.cs b/Terminal.Gui/Views/Wizard/WizardStep.cs index bc72c0c723..3efd1d5e56 100644 --- a/Terminal.Gui/Views/Wizard/WizardStep.cs +++ b/Terminal.Gui/Views/Wizard/WizardStep.cs @@ -1,209 +1,208 @@ -namespace Terminal.Gui { +namespace Terminal.Gui; + +/// +/// Represents a basic step that is displayed in a . The view is divided horizontally in two. On the left is the +/// content view where s can be added, On the right is the help for the step. +/// Set to set the help text. If the help text is empty the help pane will not +/// be shown. +/// +/// If there are no Views added to the WizardStep the (if not empty) will fill the wizard step. +/// +/// +/// If s are added, do not set to true as this will conflict +/// with the Next button of the Wizard. +/// +/// Subscribe to the event to be notified when the step is active; see also: . +/// +/// To enable or disable a step from being shown to the user, set . +/// +/// +public class WizardStep : FrameView { + ///// + ///// The title of the . + ///// + ///// The Title is only displayed when the is used as a modal pop-up (see . + //public new string Title { + // // BUGBUG: v2 - No need for this as View now has Title w/ notifications. + // get => title; + // set { + // if (!OnTitleChanging (title, value)) { + // var old = title; + // title = value; + // OnTitleChanged (old, title); + // } + // base.Title = value; + // SetNeedsDisplay (); + // } + //} + + //private string title = string.Empty; + + // The contentView works like the ContentView in FrameView. + private View contentView = new View () { Data = "WizardContentView" }; /// - /// Represents a basic step that is displayed in a . The view is divided horizontally in two. On the left is the - /// content view where s can be added, On the right is the help for the step. - /// Set to set the help text. If the help text is empty the help pane will not - /// be shown. - /// - /// If there are no Views added to the WizardStep the (if not empty) will fill the wizard step. + /// Sets or gets help text for the .If is empty + /// the help pane will not be visible and the content will fill the entire WizardStep. /// - /// - /// If s are added, do not set to true as this will conflict - /// with the Next button of the Wizard. - /// - /// Subscribe to the event to be notified when the step is active; see also: . - /// - /// To enable or disable a step from being shown to the user, set . - /// - /// - public class WizardStep : FrameView { - ///// - ///// The title of the . - ///// - ///// The Title is only displayed when the is used as a modal pop-up (see . - //public new string Title { - // // BUGBUG: v2 - No need for this as View now has Title w/ notifications. - // get => title; - // set { - // if (!OnTitleChanging (title, value)) { - // var old = title; - // title = value; - // OnTitleChanged (old, title); - // } - // base.Title = value; - // SetNeedsDisplay (); - // } - //} - - //private string title = string.Empty; - - // The contentView works like the ContentView in FrameView. - private View contentView = new View () { Data = "WizardContentView" }; - - /// - /// Sets or gets help text for the .If is empty - /// the help pane will not be visible and the content will fill the entire WizardStep. - /// - /// The help text is displayed using a read-only . - public string HelpText { - get => helpTextView.Text; - set { - helpTextView.Text = value; - ShowHide (); - SetNeedsDisplay (); - } - } - private TextView helpTextView = new TextView (); - - /// - /// Sets or gets the text for the back button. The back button will only be visible on - /// steps after the first step. - /// - /// The default text is "Back" - public string BackButtonText { get; set; } = string.Empty; - - /// - /// Sets or gets the text for the next/finish button. - /// - /// The default text is "Next..." if the Pane is not the last pane. Otherwise it is "Finish" - public string NextButtonText { get; set; } = string.Empty; - - /// - /// Initializes a new instance of the class using positioning. - /// - public WizardStep () - { - BorderStyle = LineStyle.None; - base.Add (contentView); - - helpTextView.ReadOnly = true; - helpTextView.WordWrap = true; - base.Add (helpTextView); - - // BUGBUG: v2 - Disabling scrolling for now - //var scrollBar = new ScrollBarView (helpTextView, true); - - //scrollBar.ChangedPosition += (s,e) => { - // helpTextView.TopRow = scrollBar.Position; - // if (helpTextView.TopRow != scrollBar.Position) { - // scrollBar.Position = helpTextView.TopRow; - // } - // helpTextView.SetNeedsDisplay (); - //}; - - //scrollBar.OtherScrollBarView.ChangedPosition += (s,e) => { - // helpTextView.LeftColumn = scrollBar.OtherScrollBarView.Position; - // if (helpTextView.LeftColumn != scrollBar.OtherScrollBarView.Position) { - // scrollBar.OtherScrollBarView.Position = helpTextView.LeftColumn; - // } - // helpTextView.SetNeedsDisplay (); - //}; - - //scrollBar.VisibleChanged += (s,e) => { - // if (scrollBar.Visible && helpTextView.RightOffset == 0) { - // helpTextView.RightOffset = 1; - // } else if (!scrollBar.Visible && helpTextView.RightOffset == 1) { - // helpTextView.RightOffset = 0; - // } - //}; - - //scrollBar.OtherScrollBarView.VisibleChanged += (s,e) => { - // if (scrollBar.OtherScrollBarView.Visible && helpTextView.BottomOffset == 0) { - // helpTextView.BottomOffset = 1; - // } else if (!scrollBar.OtherScrollBarView.Visible && helpTextView.BottomOffset == 1) { - // helpTextView.BottomOffset = 0; - // } - //}; - - //helpTextView.DrawContent += (s,e) => { - // scrollBar.Size = helpTextView.Lines; - // scrollBar.Position = helpTextView.TopRow; - // if (scrollBar.OtherScrollBarView != null) { - // scrollBar.OtherScrollBarView.Size = helpTextView.Maxlength; - // scrollBar.OtherScrollBarView.Position = helpTextView.LeftColumn; - // } - // scrollBar.LayoutSubviews (); - // scrollBar.Refresh (); - //}; - //base.Add (scrollBar); + /// The help text is displayed using a read-only . + public string HelpText { + get => helpTextView.Text; + set { + helpTextView.Text = value; ShowHide (); + SetNeedsDisplay (); } + } + private TextView helpTextView = new TextView (); - /// - /// Does the work to show and hide the contentView and helpView as appropriate - /// - internal void ShowHide () - { - contentView.Height = Dim.Fill (); - helpTextView.Height = Dim.Fill (); - helpTextView.Width = Dim.Fill (); - - if (contentView.InternalSubviews?.Count > 0) { - if (helpTextView.Text.Length > 0) { - contentView.Width = Dim.Percent (70); - helpTextView.X = Pos.Right (contentView); - helpTextView.Width = Dim.Fill (); - - } else { - contentView.Width = Dim.Fill (); - } - } else { - if (helpTextView.Text.Length > 0) { - helpTextView.X = 0; - } else { - // Error - no pane shown - } + /// + /// Sets or gets the text for the back button. The back button will only be visible on + /// steps after the first step. + /// + /// The default text is "Back" + public string BackButtonText { get; set; } = string.Empty; + + /// + /// Sets or gets the text for the next/finish button. + /// + /// The default text is "Next..." if the Pane is not the last pane. Otherwise it is "Finish" + public string NextButtonText { get; set; } = string.Empty; + + /// + /// Initializes a new instance of the class using positioning. + /// + public WizardStep () + { + BorderStyle = LineStyle.None; + base.Add (contentView); + + helpTextView.ReadOnly = true; + helpTextView.WordWrap = true; + base.Add (helpTextView); + + // BUGBUG: v2 - Disabling scrolling for now + //var scrollBar = new ScrollBarView (helpTextView, true); + + //scrollBar.ChangedPosition += (s,e) => { + // helpTextView.TopRow = scrollBar.Position; + // if (helpTextView.TopRow != scrollBar.Position) { + // scrollBar.Position = helpTextView.TopRow; + // } + // helpTextView.SetNeedsDisplay (); + //}; + + //scrollBar.OtherScrollBarView.ChangedPosition += (s,e) => { + // helpTextView.LeftColumn = scrollBar.OtherScrollBarView.Position; + // if (helpTextView.LeftColumn != scrollBar.OtherScrollBarView.Position) { + // scrollBar.OtherScrollBarView.Position = helpTextView.LeftColumn; + // } + // helpTextView.SetNeedsDisplay (); + //}; + + //scrollBar.VisibleChanged += (s,e) => { + // if (scrollBar.Visible && helpTextView.RightOffset == 0) { + // helpTextView.RightOffset = 1; + // } else if (!scrollBar.Visible && helpTextView.RightOffset == 1) { + // helpTextView.RightOffset = 0; + // } + //}; + + //scrollBar.OtherScrollBarView.VisibleChanged += (s,e) => { + // if (scrollBar.OtherScrollBarView.Visible && helpTextView.BottomOffset == 0) { + // helpTextView.BottomOffset = 1; + // } else if (!scrollBar.OtherScrollBarView.Visible && helpTextView.BottomOffset == 1) { + // helpTextView.BottomOffset = 0; + // } + //}; + + //helpTextView.DrawContent += (s,e) => { + // scrollBar.Size = helpTextView.Lines; + // scrollBar.Position = helpTextView.TopRow; + // if (scrollBar.OtherScrollBarView != null) { + // scrollBar.OtherScrollBarView.Size = helpTextView.Maxlength; + // scrollBar.OtherScrollBarView.Position = helpTextView.LeftColumn; + // } + // scrollBar.LayoutSubviews (); + // scrollBar.Refresh (); + //}; + //base.Add (scrollBar); + ShowHide (); + } + + /// + /// Does the work to show and hide the contentView and helpView as appropriate + /// + internal void ShowHide () + { + contentView.Height = Dim.Fill (); + helpTextView.Height = Dim.Fill (); + helpTextView.Width = Dim.Fill (); + + if (contentView.InternalSubviews?.Count > 0) { + if (helpTextView.Text.Length > 0) { + contentView.Width = Dim.Percent (70); + helpTextView.X = Pos.Right (contentView); + helpTextView.Width = Dim.Fill (); + } else { + contentView.Width = Dim.Fill (); + } + } else { + if (helpTextView.Text.Length > 0) { + helpTextView.X = 0; + } else { + // Error - no pane shown } - contentView.Visible = contentView.InternalSubviews?.Count > 0; - helpTextView.Visible = helpTextView.Text.Length > 0; + } + contentView.Visible = contentView.InternalSubviews?.Count > 0; + helpTextView.Visible = helpTextView.Text.Length > 0; + } - /// - /// Add the specified to the . - /// - /// to add to this container - public override void Add (View view) - { - contentView.Add (view); - if (view.CanFocus) { - CanFocus = true; - } - ShowHide (); + /// + /// Add the specified to the . + /// + /// to add to this container + public override void Add (View view) + { + contentView.Add (view); + if (view.CanFocus) { + CanFocus = true; } + ShowHide (); + } - /// - /// Removes a from . - /// - /// - /// - public override void Remove (View view) - { - if (view == null) { - return; - } + /// + /// Removes a from . + /// + /// + /// + public override void Remove (View view) + { + if (view == null) { + return; + } - SetNeedsDisplay (); - var touched = view.Frame; - contentView.Remove (view); + SetNeedsDisplay (); + var touched = view.Frame; + contentView.Remove (view); - if (contentView.InternalSubviews.Count < 1) { - this.CanFocus = false; - } - ShowHide (); + if (contentView.InternalSubviews.Count < 1) { + this.CanFocus = false; } + ShowHide (); + } - /// - /// Removes all s from the . - /// - /// - /// - public override void RemoveAll () - { - contentView.RemoveAll (); - ShowHide (); - } + /// + /// Removes all s from the . + /// + /// + /// + public override void RemoveAll () + { + contentView.RemoveAll (); + ShowHide (); + } - } // end of WizardStep class -} \ No newline at end of file +} // end of WizardStep class \ No newline at end of file