瀏覽代碼

Adds ArragngementEditor.
Fixes #3735

Tig 10 月之前
父節點
當前提交
80bae9f135

+ 5 - 0
Terminal.Gui/View/View.Drawing.cs

@@ -21,6 +21,11 @@ public partial class View // Drawing APIs
             if (_colorScheme != value)
             {
                 _colorScheme = value;
+
+                if (Border is {} && Border.LineStyle != LineStyle.None && Border.ColorScheme is { })
+                {
+                    Border.ColorScheme = _colorScheme;
+                }
                 SetNeedsDisplay ();
             }
         }

+ 28 - 0
Terminal.Gui/Views/Slider.cs

@@ -1466,6 +1466,34 @@ public class Slider<T> : View, IOrientation
 
     private Dictionary<int, SliderOption<T>> GetSetOptionDictionary () { return _setOptions.ToDictionary (e => e, e => _options [e]); }
 
+    /// <summary>
+    /// Sets or unsets <paramref name="optionIndex"/> based on <paramref name="set"/>.
+    /// </summary>
+    /// <param name="optionIndex">The option to change.</param>
+    /// <param name="set">If <see langword="true"/>, sets the option. Unsets it otherwise.</param>
+    public void ChangeOption (int optionIndex, bool set)
+    {
+        if (set)
+        {
+            if (!_setOptions.Contains (optionIndex))
+            {
+                _setOptions.Add (optionIndex);
+                _options [optionIndex].OnSet ();
+            }
+        }
+        else
+        {
+            if (_setOptions.Contains (optionIndex))
+            {
+                _setOptions.Remove (optionIndex);
+                _options [optionIndex].OnUnSet ();
+            }
+        }
+
+        // Raise slider changed event.
+        OnOptionsChanged ();
+    }
+
     private void SetFocusedOption ()
     {
         switch (_config._type)

+ 240 - 0
UICatalog/Scenarios/ArrangementEditor.cs

@@ -0,0 +1,240 @@
+#nullable enable
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Terminal.Gui;
+
+namespace UICatalog.Scenarios;
+
+/// <summary>
+///     Provides an editor UI for the Margin, Border, and Padding of a View.
+/// </summary>
+public sealed class ArrangementEditor : View
+{
+    public ArrangementEditor ()
+    {
+        Title = "ArrangementEditor";
+
+        Width = Dim.Auto (DimAutoStyle.Content);
+        Height = Dim.Auto (DimAutoStyle.Content);
+
+        CanFocus = true;
+
+        TabStop = TabBehavior.TabGroup;
+
+        Initialized += ArrangementEditor_Initialized;
+
+        _arrangementSlider.Options = new List<SliderOption<ViewArrangement>> ();
+
+        _arrangementSlider.Options.Add (new SliderOption<ViewArrangement>
+        {
+            Legend = ViewArrangement.Movable.ToString (),
+            Data = ViewArrangement.Movable
+        });
+
+        _arrangementSlider.Options.Add (new SliderOption<ViewArrangement>
+        {
+            Legend = ViewArrangement.LeftResizable.ToString (),
+            Data = ViewArrangement.LeftResizable
+        });
+
+        _arrangementSlider.Options.Add (new SliderOption<ViewArrangement>
+        {
+            Legend = ViewArrangement.RightResizable.ToString (),
+            Data = ViewArrangement.RightResizable
+        });
+
+        _arrangementSlider.Options.Add (new SliderOption<ViewArrangement>
+        {
+            Legend = ViewArrangement.TopResizable.ToString (),
+            Data = ViewArrangement.TopResizable
+        });
+
+        _arrangementSlider.Options.Add (new SliderOption<ViewArrangement>
+        {
+            Legend = ViewArrangement.BottomResizable.ToString (),
+            Data = ViewArrangement.BottomResizable
+        });
+
+        _arrangementSlider.Options.Add (new SliderOption<ViewArrangement>
+        {
+            Legend = ViewArrangement.Overlapped.ToString (),
+            Data = ViewArrangement.Overlapped
+        });
+
+        Add (_arrangementSlider);
+    }
+
+    private View? _viewToEdit;
+
+    private Label? _lblView; // Text describing the view being edited
+
+    private Slider<ViewArrangement> _arrangementSlider = new Slider<ViewArrangement> ()
+    {
+        Orientation = Orientation.Vertical,
+        UseMinimumSize = true,
+        Type = SliderType.Multiple,
+        AllowEmpty = true,
+        BorderStyle = LineStyle.Dotted,
+        Title = "_Arrangement",
+    };
+
+    /// <summary>
+    ///     Gets or sets whether the ArrangementEditor should automatically select the View to edit
+    ///     based on the values of <see cref="AutoSelectSuperView"/> and <see cref="AutoSelect"/>.
+    /// </summary>
+    public bool AutoSelectViewToEdit { get; set; }
+
+    /// <summary>
+    ///     Gets or sets the View that will scope the behavior of <see cref="AutoSelectViewToEdit"/>.
+    /// </summary>
+    public View? AutoSelectSuperView { get; set; }
+
+    public View? ViewToEdit
+    {
+        get => _viewToEdit;
+        set
+        {
+            if (_viewToEdit == value)
+            {
+                return;
+            }
+
+            _arrangementSlider.OptionsChanged -= ArrangementSliderOnOptionsChanged;
+
+            _viewToEdit = value;
+            // Set the appropriate options in the slider based on _viewToEdit.Arrangement
+            if (_viewToEdit is { })
+            {
+                _arrangementSlider.Options.ForEach (option =>
+                                                    {
+                                                        _arrangementSlider.ChangeOption (_arrangementSlider.Options.IndexOf (option), (_viewToEdit.Arrangement & option.Data) == option.Data);
+                                                    });
+            }
+
+            _arrangementSlider.OptionsChanged += ArrangementSliderOnOptionsChanged;
+
+            if (_lblView is { })
+            {
+                _lblView.Text = $"{_viewToEdit?.GetType ().Name}: {_viewToEdit?.Id}" ?? string.Empty;
+            }
+        }
+    }
+
+
+    private void NavigationOnFocusedChanged (object? sender, EventArgs e)
+    {
+        if (AutoSelectSuperView is null)
+        {
+            return;
+        }
+
+        View? view = Application.Navigation!.GetFocused ();
+
+        if (ApplicationNavigation.IsInHierarchy (this, view))
+        {
+            return;
+        }
+
+        if (!ApplicationNavigation.IsInHierarchy (AutoSelectSuperView, view))
+        {
+            return;
+        }
+
+        if (view is { } and not Adornment)
+        {
+            ViewToEdit = view;
+        }
+    }
+
+    private void ApplicationOnMouseEvent (object? sender, MouseEvent e)
+    {
+        if (e.Flags != MouseFlags.Button1Clicked || !AutoSelectViewToEdit)
+        {
+            return;
+        }
+
+        if ((AutoSelectSuperView is { } && !AutoSelectSuperView.FrameToScreen ().Contains (e.Position))
+            || FrameToScreen ().Contains (e.Position))
+        {
+            return;
+        }
+
+        View? view = e.View;
+
+        if (view is Adornment adornment)
+        {
+            view = adornment.Parent;
+        }
+
+        if (view is { } and not Adornment)
+        {
+            ViewToEdit = view;
+        }
+    }
+
+    private void ArrangementEditor_Initialized (object? sender, EventArgs e)
+    {
+        BorderStyle = LineStyle.Dotted;
+
+        var expandButton = new ExpanderButton
+        {
+            Orientation = Orientation.Horizontal
+        };
+        Border.Add (expandButton);
+
+        _lblView = new ()
+        {
+            X = 0,
+            Y = 0,
+            Height = 2
+        };
+        _lblView.TextFormatter.WordWrap = true;
+        _lblView.TextFormatter.MultiLine = true;
+        _lblView.HotKeySpecifier = (Rune)'\uffff';
+        _lblView.Width = Dim.Width (_arrangementSlider);
+        Add (_lblView);
+
+        _arrangementSlider.Y = Pos.Bottom (_lblView);
+
+        _arrangementSlider.OptionsChanged += ArrangementSliderOnOptionsChanged;
+
+        Application.MouseEvent += ApplicationOnMouseEvent;
+        Application.Navigation!.FocusedChanged += NavigationOnFocusedChanged;
+    }
+
+    private void ArrangementSliderOnOptionsChanged (object? sender, SliderEventArgs<ViewArrangement> e)
+    {
+        if (_viewToEdit is { })
+        {
+            // Set the arrangement based on the selected options
+            ViewArrangement arrangement = ViewArrangement.Fixed;
+            foreach (var option in e.Options)
+            {
+                arrangement |= option.Value.Data;
+            }
+
+            _viewToEdit.Arrangement = arrangement;
+
+            if (_viewToEdit.Arrangement.HasFlag (ViewArrangement.Overlapped))
+            {
+                _viewToEdit.ShadowStyle = ShadowStyle.Transparent;
+                _viewToEdit.ColorScheme = Colors.ColorSchemes ["Toplevel"];
+            }
+            else
+            {
+                _viewToEdit.ShadowStyle = ShadowStyle.None;
+                _viewToEdit.ColorScheme = _viewToEdit.SuperView.ColorScheme;
+            }
+
+            if (_viewToEdit.Arrangement.HasFlag (ViewArrangement.Movable))
+            {
+                _viewToEdit.BorderStyle = LineStyle.Double;
+            }
+            else
+            {
+                _viewToEdit.BorderStyle = LineStyle.Single;
+            }
+        }
+    }
+}

+ 17 - 4
UICatalog/Scenarios/Navigation.cs

@@ -21,19 +21,30 @@ public class Navigation : Scenario
             TabStop = TabBehavior.TabGroup
         };
 
-        var editor = new AdornmentsEditor
+        var adornmentsEditor = new AdornmentsEditor
         {
             X = 0,
             Y = 0,
             AutoSelectViewToEdit = true,
             TabStop = TabBehavior.NoStop
         };
-        app.Add (editor);
+        app.Add (adornmentsEditor);
+
+        var arrangementEditor = new ArrangementEditor()
+        {
+            X = Pos.Right (adornmentsEditor),
+            Y = 0,
+            //Height = Dim.Fill(),
+            AutoSelectViewToEdit = true,
+            TabStop = TabBehavior.NoStop
+        };
+        app.Add (arrangementEditor);
 
         FrameView testFrame = new ()
         {
             Title = "_1 Test Frame",
-            X = Pos.Right (editor),
+            X = Pos.Right (arrangementEditor),
+            Y = 0,
             Width = Dim.Fill (),
             Height = Dim.Fill ()
         };
@@ -182,7 +193,9 @@ public class Navigation : Scenario
 
         testFrame.Add (button);
 
-        editor.AutoSelectSuperView = testFrame;
+        adornmentsEditor.AutoSelectSuperView = testFrame;
+        arrangementEditor.AutoSelectSuperView = testFrame;
+
         testFrame.SetFocus ();
         Application.Run (app);
         timer.Close ();