using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Windows; using System.Windows.Controls; using InABox.Configuration; using InABox.Core; namespace InABox.Wpf; public interface IPanelActionItem { } public interface IPanelActionEntry { object? Data { get; set; } string? Caption { get; set; } Bitmap? Image { get; set; } void Execute(); } public class PanelActionEntry : DependencyObject, IPanelActionEntry { public static readonly DependencyProperty DataProperty = DependencyProperty.Register( nameof(Data), typeof(T), typeof(PanelActionEntry) ); public T? Data { get; set; } object? IPanelActionEntry.Data { get => this.Data; set => this.Data = value == null ? default(T) : (T)value; } public static readonly DependencyProperty CaptionProperty = DependencyProperty.Register( nameof(Caption), typeof(string), typeof(PanelActionEntry), new PropertyMetadata("") ); public string? Caption { get; set; } public static readonly DependencyProperty ImageProperty = DependencyProperty.Register( nameof(Image), typeof(Bitmap), typeof(PanelActionEntry) ); public Bitmap? Image { get => GetValue(ImageProperty) as Bitmap; set => SetValue(ImageProperty, value); } public Action>? OnExecute { get; set; } public PanelActionEntry() { } public PanelActionEntry(string? caption, Bitmap? image, T? data, Action>? onExecute) { Data = data; Caption = caption; Image = image; OnExecute = onExecute; } public void Execute() { OnExecute?.Invoke(this); } } public class PanelAction : DependencyObject, IPanelActionItem { public Func? OnPopulate { get; set; } public Action? OnExecute { get; set; } public static readonly DependencyProperty IsEnabledProperty = DependencyProperty.Register( nameof(IsEnabled), typeof(bool), typeof(PanelAction), new PropertyMetadata(true) ); public bool IsEnabled { get => (bool)GetValue(IsEnabledProperty); set => SetValue(IsEnabledProperty, value); } public static readonly DependencyProperty VisibilityProperty = DependencyProperty.Register( nameof(Visibility), typeof(Visibility), typeof(PanelAction), new PropertyMetadata(Visibility.Visible) ); public Visibility Visibility { get => (Visibility)GetValue(VisibilityProperty); set => SetValue(VisibilityProperty, value); } public static readonly DependencyProperty CaptionProperty = DependencyProperty.Register( nameof(Caption), typeof(string), typeof(PanelAction), new PropertyMetadata("") ); public string Caption { get => (string)GetValue(CaptionProperty); set => SetValue(CaptionProperty, value); } public static readonly DependencyProperty ImageProperty = DependencyProperty.Register( nameof(Image), typeof(Bitmap), typeof(PanelAction) ); public Bitmap? Image { get => GetValue(ImageProperty) as Bitmap; set => SetValue(ImageProperty, value); } public static readonly DependencyProperty MenuProperty = DependencyProperty.Register( nameof(Menu), typeof(ContextMenu), typeof(PanelAction) ); public ContextMenu? Menu { get => GetValue(MenuProperty) as ContextMenu; set => SetValue(MenuProperty, value); } public PanelAction() { } public PanelAction(string caption, Bitmap? image, Action? onExecute, Func? onPopulate = null) { Caption = caption; Image = image; OnPopulate = onPopulate; OnExecute = onExecute; } public void Execute() { OnExecute?.Invoke(this); } public IPanelActionEntry[]? Populate() { return OnPopulate?.Invoke(this); } } public class PanelActionSeparator : IPanelActionItem { } public interface ICorePanel { void Setup(); /// /// Shutdown the panel. /// /// If the operation can be cancelled, this is not void Shutdown(CancelEventArgs? cancel); void Refresh(); } public interface IBasePanel : ICorePanel, IDataModelSource { bool IsReady { get; set; } void CreateToolbarButtons(IPanelHost host); Dictionary Selected(); void Heartbeat(TimeSpan time); } public interface IPanel : IBasePanel { } public interface IPropertiesPanel where TProperties : BaseObject, IGlobalConfigurationSettings, new() { public TProperties Properties { get; set; } } public interface IPropertiesPanel : IPropertiesPanel where TProperties : BaseObject, IGlobalConfigurationSettings, new() where TSecurity : ISecurityDescriptor, new() { } public interface IPanelHost { void CreatePanelAction(PanelAction action); void CreateReport(PanelAction action); void CreateSetupAction(PanelAction action); void CreateSetupSeparator(); } public static class IPanelHostExtensions { public static void CreateSetupAction(this IPanelHost host, string caption, Bitmap image, Action onExecute, ContextMenu? menu = null) { host.CreateSetupAction(new PanelAction(caption, image, onExecute) { Menu = menu }); } public static void CreateSetupActionIf(this IPanelHost host, string caption, Bitmap image, Action onExecute, bool canView, ContextMenu? menu = null) { if (canView) { host.CreateSetupAction(new PanelAction(caption, image, onExecute) { Menu = menu }); } } public static void CreateSetupActionIf(this IPanelHost host, string caption, Bitmap image, Action onExecute, ContextMenu? menu = null) where TSecurity : ISecurityDescriptor, new() { host.CreateSetupActionIf(caption, image, onExecute, Security.IsAllowed(), menu); } public static void CreateSetupActionIfCanView(this IPanelHost host, string caption, Bitmap image, Action onExecute, ContextMenu? menu = null) where T : Entity, new() { host.CreateSetupActionIf(caption, image, onExecute, Security.CanView(), menu); } } /// /// Implement this interface to cause a class to act as a host of . Then, you can use the extension functions /// and /// to interact with it. /// /// /// If you mark an as an , then the shutdown method is called automatically by . /// public interface ISubPanelHost { List SubPanels { get; } static ISubPanelHost Global = new GlobalSubPanelHost(); private class GlobalSubPanelHost : ISubPanelHost { public List SubPanels { get; set; } = new(); } } public static class ISubPanelHostExtensions { public static void ShutdownSubPanels(this ISubPanelHost host, CancelEventArgs? cancel) { ISubPanel[] panels; lock (host.SubPanels) { panels = host.SubPanels.ToArray(); host.SubPanels.Clear(); var isCancelled = false; foreach(var panel in panels) { if (isCancelled) { host.SubPanels.Add(panel); } else { panel.Shutdown(cancel); if (cancel?.Cancel == true) { isCancelled = true; host.SubPanels.Add(panel); } } } } } public static void AddSubPanel(this ISubPanelHost host, ISubPanel panel) { host.SubPanels.Add(panel); panel.SubPanelClosed += p => { lock (host.SubPanels) { host.SubPanels.Remove(p); } }; } } /// /// An is a non-modal window, which is tied to a parent /// public interface ISubPanel { public delegate void ClosedEvent(ISubPanel panel); /// /// Event to be called when a sub-panel closes itself; in this case, will not be called. This allows /// the host to get rid of the sub-panel, instead of keeping it forever. /// /// /// You may call this after has been called. /// public event ClosedEvent? SubPanelClosed; /// /// Shutdown the panel. /// /// If the operation can be cancelled, this is not void Shutdown(CancelEventArgs? cancel); }