소스 검색

Merge develop.

BDisp 2 년 전
부모
커밋
bad23db442

+ 1 - 1
.github/workflows/api-docs.yml

@@ -13,7 +13,7 @@ jobs:
       uses: actions/checkout@v2
 
     - name: Setup .NET Core
-      uses: actions/[email protected].2
+      uses: actions/[email protected].3
       with:
         dotnet-version: 6.0.100
     

+ 1 - 1
.github/workflows/dotnet-core.yml

@@ -15,7 +15,7 @@ jobs:
     - uses: actions/checkout@v3
 
     - name: Setup .NET Core
-      uses: actions/[email protected].2
+      uses: actions/[email protected].3
       with:
         dotnet-version: 6.0.100
 

+ 1 - 1
.github/workflows/publish.yml

@@ -30,7 +30,7 @@ jobs:
         echo "CommitsSinceVersionSource: ${{ steps.gitversion.outputs.CommitsSinceVersionSource }}"
 
     - name: Setup dotnet
-      uses: actions/[email protected].2
+      uses: actions/[email protected].3
       with:
         dotnet-version: 6.0.100
 

+ 1 - 1
Terminal.Gui/Core/PosDim.cs

@@ -593,7 +593,7 @@ namespace Terminal.Gui {
 
 		internal class DimCombine : Dim {
 			internal Dim left, right;
-			bool add;
+			internal bool add;
 			public DimCombine (bool add, Dim left, Dim right)
 			{
 				this.left = left;

+ 95 - 64
Terminal.Gui/Core/View.cs

@@ -2157,19 +2157,7 @@ namespace Terminal.Gui {
 			} else {
 				actX = x?.Anchor (hostFrame.Width) ?? 0;
 
-				switch (width) {
-				case null:
-					actW = AutoSize ? s.Width : hostFrame.Width;
-					break;
-				case Dim.DimFactor factor when !factor.IsFromRemaining ():
-					actW = width.Anchor (hostFrame.Width);
-					actW = AutoSize && s.Width > actW ? s.Width : actW;
-					break;
-				default:
-					actW = Math.Max (width.Anchor (hostFrame.Width - actX), 0);
-					actW = AutoSize && s.Width > actW ? s.Width : actW;
-					break;
-				}
+				actW = Math.Max (CalculateActualWidth (width, hostFrame, actX, s), 0);
 			}
 
 			if (y is Pos.PosCenter) {
@@ -2183,29 +2171,77 @@ namespace Terminal.Gui {
 			} else {
 				actY = y?.Anchor (hostFrame.Height) ?? 0;
 
-				switch (height) {
-				case null:
-					actH = AutoSize ? s.Height : hostFrame.Height;
-					break;
-				case Dim.DimFactor factor when !factor.IsFromRemaining ():
-					actH = height.Anchor (hostFrame.Height);
-					actH = AutoSize && s.Height > actH ? s.Height : actH;
-					break;
-				default:
-					actH = Math.Max (height.Anchor (hostFrame.Height - actY), 0);
-					actH = AutoSize && s.Height > actH ? s.Height : actH;
-					break;
-				}
+				actH = Math.Max (CalculateActualHight (height, hostFrame, actY, s), 0);
 			}
 
 			var r = new Rect (actX, actY, actW, actH);
 			if (Frame != r) {
-				Frame = new Rect (actX, actY, actW, actH);
+				Frame = r;
 				if (!SetMinWidthHeight ())
 					TextFormatter.Size = GetBoundsTextFormatterSize ();
 			}
 		}
 
+		private int CalculateActualWidth (Dim width, Rect hostFrame, int actX, Size s)
+		{
+			int actW;
+			switch (width) {
+			case null:
+				actW = AutoSize ? s.Width : hostFrame.Width;
+				break;
+			case Dim.DimCombine combine:
+				int leftActW = CalculateActualWidth (combine.left, hostFrame, actX, s);
+				int rightActW = CalculateActualWidth (combine.right, hostFrame, actX, s);
+				if (combine.add) {
+					actW = leftActW + rightActW;
+				} else {
+					actW = leftActW - rightActW;
+				}
+				actW = AutoSize && s.Width > actW ? s.Width : actW;
+				break;
+			case Dim.DimFactor factor when !factor.IsFromRemaining ():
+				actW = width.Anchor (hostFrame.Width);
+				actW = AutoSize && s.Width > actW ? s.Width : actW;
+				break;
+			default:
+				actW = Math.Max (width.Anchor (hostFrame.Width - actX), 0);
+				actW = AutoSize && s.Width > actW ? s.Width : actW;
+				break;
+			}
+
+			return actW;
+		}
+
+		private int CalculateActualHight (Dim height, Rect hostFrame, int actY, Size s)
+		{
+			int actH;
+			switch (height) {
+			case null:
+				actH = AutoSize ? s.Height : hostFrame.Height;
+				break;
+			case Dim.DimCombine combine:
+				int leftActH = CalculateActualHight (combine.left, hostFrame, actY, s);
+				int rightActH = CalculateActualHight (combine.right, hostFrame, actY, s);
+				if (combine.add) {
+					actH = leftActH + rightActH;
+				} else {
+					actH = leftActH - rightActH;
+				}
+				actH = AutoSize && s.Height > actH ? s.Height : actH;
+				break;
+			case Dim.DimFactor factor when !factor.IsFromRemaining ():
+				actH = height.Anchor (hostFrame.Height);
+				actH = AutoSize && s.Height > actH ? s.Height : actH;
+				break;
+			default:
+				actH = Math.Max (height.Anchor (hostFrame.Height - actY), 0);
+				actH = AutoSize && s.Height > actH ? s.Height : actH;
+				break;
+			}
+
+			return actH;
+		}
+
 		// https://en.wikipedia.org/wiki/Topological_sorting
 		List<View> TopologicalSort (IEnumerable<View> nodes, ICollection<(View From, View To)> edges)
 		{
@@ -2328,44 +2364,40 @@ namespace Terminal.Gui {
 			void CollectPos (Pos pos, View from, ref HashSet<View> nNodes, ref HashSet<(View, View)> nEdges)
 			{
 				switch (pos) {
-				case Pos.PosView pv: {
-						if (pv.Target != this) {
-							nEdges.Add ((pv.Target, from));
-						}
-						foreach (var v in from.InternalSubviews) {
-							CollectAll (v, ref nNodes, ref nEdges);
-						}
-						return;
+				case Pos.PosView pv:
+					if (pv.Target != this) {
+						nEdges.Add ((pv.Target, from));
 					}
-				case Pos.PosCombine pc: {
-						foreach (var v in from.InternalSubviews) {
-							CollectPos (pc.left, from, ref nNodes, ref nEdges);
-							CollectPos (pc.right, from, ref nNodes, ref nEdges);
-						}
-						break;
+					foreach (var v in from.InternalSubviews) {
+						CollectAll (v, ref nNodes, ref nEdges);
 					}
+					return;
+				case Pos.PosCombine pc:
+					foreach (var v in from.InternalSubviews) {
+						CollectPos (pc.left, from, ref nNodes, ref nEdges);
+						CollectPos (pc.right, from, ref nNodes, ref nEdges);
+					}
+					break;
 				}
 			}
 
 			void CollectDim (Dim dim, View from, ref HashSet<View> nNodes, ref HashSet<(View, View)> nEdges)
 			{
 				switch (dim) {
-				case Dim.DimView dv: {
-						if (dv.Target != this) {
-							nEdges.Add ((dv.Target, from));
-						}
-						foreach (var v in from.InternalSubviews) {
-							CollectAll (v, ref nNodes, ref nEdges);
-						}
-						return;
+				case Dim.DimView dv:
+					if (dv.Target != this) {
+						nEdges.Add ((dv.Target, from));
 					}
-				case Dim.DimCombine dc: {
-						foreach (var v in from.InternalSubviews) {
-							CollectDim (dc.left, from, ref nNodes, ref nEdges);
-							CollectDim (dc.right, from, ref nNodes, ref nEdges);
-						}
-						break;
+					foreach (var v in from.InternalSubviews) {
+						CollectAll (v, ref nNodes, ref nEdges);
 					}
+					return;
+				case Dim.DimCombine dc:
+					foreach (var v in from.InternalSubviews) {
+						CollectDim (dc.left, from, ref nNodes, ref nEdges);
+						CollectDim (dc.right, from, ref nNodes, ref nEdges);
+					}
+					break;
 				}
 			}
 
@@ -2954,16 +2986,15 @@ namespace Terminal.Gui {
 				h = Height.Anchor (h);
 				canSetHeight = !ForceValidatePosDim;
 				break;
-			case Dim.DimFactor factor: {
-					// Tries to get the SuperView height otherwise the view height.
-					var sh = SuperView != null ? SuperView.Frame.Height : h;
-					if (factor.IsFromRemaining ()) {
-						sh -= Frame.Y;
-					}
-					h = Height.Anchor (sh);
-					canSetHeight = !ForceValidatePosDim;
-					break;
+			case Dim.DimFactor factor:
+				// Tries to get the SuperView height otherwise the view height.
+				var sh = SuperView != null ? SuperView.Frame.Height : h;
+				if (factor.IsFromRemaining ()) {
+					sh -= Frame.Y;
 				}
+				h = Height.Anchor (sh);
+				canSetHeight = !ForceValidatePosDim;
+				break;
 			default:
 				canSetHeight = true;
 				break;

+ 2 - 1
Terminal.Gui/Views/Menu.cs

@@ -758,6 +758,7 @@ namespace Terminal.Gui {
 					return true;
 				var item = barItems.Children [meY];
 				if (item == null || !item.IsEnabled ()) disabled = true;
+				if (disabled) return true;
 				current = meY;
 				if (item != null && !disabled)
 					RunSelected ();
@@ -1074,7 +1075,7 @@ namespace Terminal.Gui {
 				if (i == selected && IsMenuOpen) {
 					hotColor = i == selected ? ColorScheme.HotFocus : ColorScheme.HotNormal;
 					normalColor = i == selected ? ColorScheme.Focus : GetNormalColor ();
-				} else { 
+				} else {
 					hotColor = ColorScheme.HotNormal;
 					normalColor = GetNormalColor ();
 				}

+ 9 - 8
Terminal.Gui/Views/TreeView.cs

@@ -140,12 +140,12 @@ namespace Terminal.Gui {
 		/// <value></value>
 		public MouseFlags? ObjectActivationButton { get; set; } = MouseFlags.Button1DoubleClicked;
 
-		
+
 		/// <summary>
 		/// Delegate for multi colored tree views.  Return the <see cref="ColorScheme"/> to use
 		/// for each passed object or null to use the default.
 		/// </summary>
-		public Func<T,ColorScheme> ColorGetter {get;set;}
+		public Func<T, ColorScheme> ColorGetter { get; set; }
 
 		/// <summary>
 		/// Secondary selected regions of tree when <see cref="MultiSelect"/> is true
@@ -227,14 +227,15 @@ namespace Terminal.Gui {
 		/// Defaults to <see cref="CursorVisibility.Invisible"/>
 		/// </summary>
 		public CursorVisibility DesiredCursorVisibility {
-			get { 
+			get {
 				return MultiSelect ? desiredCursorVisibility : CursorVisibility.Invisible;
 			}
 			set {
-				desiredCursorVisibility = value;
-
-				if (desiredCursorVisibility != value && HasFocus) {
-					Application.Driver.SetCursorVisibility (DesiredCursorVisibility);
+				if (desiredCursorVisibility != value) {
+					desiredCursorVisibility = value;
+					if (HasFocus) {
+						Application.Driver.SetCursorVisibility (DesiredCursorVisibility);
+					}
 				}
 			}
 		}
@@ -626,7 +627,7 @@ namespace Terminal.Gui {
 		/// </summary>
 		/// <param name="toFind"></param>
 		/// <returns></returns>
-		public int? GetObjectRow(T toFind)
+		public int? GetObjectRow (T toFind)
 		{
 			var idx = BuildLineMap ().IndexOf (o => o.Model.Equals (toFind));
 

+ 37 - 0
UnitTests/DimTests.cs

@@ -1246,5 +1246,42 @@ namespace Terminal.Gui.Core {
 			dim2 = Dim.Function (f2);
 			Assert.NotEqual (dim1, dim2);
 		}
+
+		[Theory, AutoInitShutdown]
+		[InlineData (0, true)]
+		[InlineData (0, false)]
+		[InlineData (50, true)]
+		[InlineData (50, false)]
+
+		public void DimPercentPlusOne (int startingDistance, bool testHorizontal)
+		{
+			var container = new View {
+				Width = 100,
+				Height = 100,
+			};
+
+			var label = new Label {
+				X = testHorizontal ? startingDistance : 0,
+				Y = testHorizontal ? 0 : startingDistance,
+				Width = testHorizontal ? Dim.Percent (50) + 1 : 1,
+				Height = testHorizontal ? 1 : Dim.Percent (50) + 1,
+			};
+
+			container.Add (label);
+			Application.Top.Add (container);
+			Application.Top.LayoutSubviews ();
+
+
+			Assert.Equal (100, container.Frame.Width);
+			Assert.Equal (100, container.Frame.Height);
+
+			if (testHorizontal) {
+				Assert.Equal (51, label.Frame.Width);
+				Assert.Equal (1, label.Frame.Height);
+			} else {
+				Assert.Equal (1, label.Frame.Width);
+				Assert.Equal (51, label.Frame.Height);
+			}
+		}
 	}
 }

+ 85 - 8
UnitTests/MenuTests.cs

@@ -1133,8 +1133,8 @@ Edit
 			string padding (int i)
 			{
 				int n = 0;
-				while (i > 0){
-					n += Menus [i-1].TitleLength + 2;
+				while (i > 0) {
+					n += Menus [i - 1].TitleLength + 2;
 					i--;
 				}
 				return new string (' ', n);
@@ -1153,12 +1153,12 @@ Edit
 			public string expectedBottomRow (int i) => $"{d.LLCorner}{new String (d.HLine.ToString () [0], Menus [i].Children [0].TitleLength + 3)}{d.LRCorner}  \n";
 
 			// The fulll expected string for an open sub menu
-			public string expectedSubMenuOpen (int i) => ClosedMenuText + 
+			public string expectedSubMenuOpen (int i) => ClosedMenuText +
 				(Menus [i].Children.Length > 0 ?
 					padding (i) + expectedTopRow (i) +
 					padding (i) + expectedMenuItemRow (i) +
-					padding (i) + expectedBottomRow (i) 
-				: 
+					padding (i) + expectedBottomRow (i)
+				:
 				"");
 
 			public ExpectedMenuBar (MenuBarItem [] menus) : base (menus)
@@ -1481,14 +1481,14 @@ Edit
 
 			MenuBarItem [] items = new MenuBarItem [expectedMenu.Menus.Length];
 			for (var i = 0; i < expectedMenu.Menus.Length; i++) {
-				items [i] = new MenuBarItem (expectedMenu.Menus [i].Title, expectedMenu.Menus [i].Children.Length > 0 
+				items [i] = new MenuBarItem (expectedMenu.Menus [i].Title, expectedMenu.Menus [i].Children.Length > 0
 					? new MenuItem [] {
 						new MenuItem (expectedMenu.Menus [i].Children [0].Title, "", null),
-					} 
+					}
 					: Array.Empty<MenuItem> ());
 			}
 			var menu = new MenuBar (items);
-			
+
 			var tf = new TextField () { Y = 2, Width = 10 };
 			Application.Top.Add (menu, tf);
 
@@ -1559,5 +1559,82 @@ Edit
 			Assert.True (menu.ProcessHotKey (new KeyEvent (Key.F10 | Key.ShiftMask, new KeyModifiers ())));
 			Assert.False (menu.IsMenuOpen);
 		}
+
+		[Fact, AutoInitShutdown]
+		public void Disabled_MenuItem_Is_Never_Selected ()
+		{
+			var menu = new MenuBar (new MenuBarItem [] {
+				new MenuBarItem ("Menu", new MenuItem [] {
+					new MenuItem ("Enabled 1", "", null),
+					new MenuItem ("Disabled", "", null, () => false),
+					null,
+					new MenuItem ("Enabled 2", "", null)
+				})
+			});
+
+			var top = Application.Top;
+			top.Add (menu);
+			Application.Begin (top);
+
+			var attributes = new Attribute [] {
+				// 0
+				menu.ColorScheme.Normal,
+				// 1
+				menu.ColorScheme.Focus,
+				// 2
+				menu.ColorScheme.Disabled
+			};
+
+			TestHelpers.AssertDriverColorsAre (@"
+00000000000000", attributes);
+
+			Assert.True (menu.MouseEvent (new MouseEvent {
+				X = 0,
+				Y = 0,
+				Flags = MouseFlags.Button1Pressed,
+				View = menu
+			}));
+			top.Redraw (top.Bounds);
+			TestHelpers.AssertDriverColorsAre (@"
+11111100000000
+00000000000000
+01111111111110
+02222222222220
+00000000000000
+00000000000000
+00000000000000", attributes);
+
+			Assert.True (top.Subviews [1].MouseEvent (new MouseEvent {
+				X = 0,
+				Y = 2,
+				Flags = MouseFlags.Button1Clicked,
+				View = top.Subviews [1]
+			}));
+			top.Subviews [1].Redraw (top.Bounds);
+			TestHelpers.AssertDriverColorsAre (@"
+11111100000000
+00000000000000
+01111111111110
+02222222222220
+00000000000000
+00000000000000
+00000000000000", attributes);
+
+			Assert.True (top.Subviews [1].MouseEvent (new MouseEvent {
+				X = 0,
+				Y = 2,
+				Flags = MouseFlags.ReportMousePosition,
+				View = top.Subviews [1]
+			}));
+			top.Subviews [1].Redraw (top.Bounds);
+			TestHelpers.AssertDriverColorsAre (@"
+11111100000000
+00000000000000
+01111111111110
+02222222222220
+00000000000000
+00000000000000
+00000000000000", attributes);
+		}
 	}
 }

+ 35 - 0
UnitTests/PosTests.cs

@@ -1032,5 +1032,40 @@ namespace Terminal.Gui.Core {
 			pos2 = Pos.Function (f2);
 			Assert.NotEqual (pos1, pos2);
 		}
+
+		[Theory, AutoInitShutdown]
+		[InlineData (true)]
+		[InlineData (false)]
+
+		public void PosPercentPlusOne (bool testHorizontal)
+		{
+			var container = new View {
+				Width = 100,
+				Height = 100,
+			};
+
+			var label = new Label {
+				X = testHorizontal ? Pos.Percent (50) + Pos.Percent (10) + 1 : 1,
+				Y = testHorizontal ? 1 : Pos.Percent (50) + Pos.Percent (10) + 1,
+				Width = 10,
+				Height = 10,
+			};
+
+			container.Add (label);
+			Application.Top.Add (container);
+			Application.Top.LayoutSubviews ();
+
+
+			Assert.Equal (100, container.Frame.Width);
+			Assert.Equal (100, container.Frame.Height);
+
+			if (testHorizontal) {
+				Assert.Equal (61, label.Frame.X);
+				Assert.Equal (1, label.Frame.Y);
+			} else {
+				Assert.Equal (1, label.Frame.X);
+				Assert.Equal (61, label.Frame.Y);
+			}
+		}
 	}
 }

+ 48 - 24
UnitTests/TreeViewTests.cs

@@ -839,26 +839,26 @@ namespace Terminal.Gui.Views {
 			Assert.Equal (0, tv.GetObjectRow (n2));
 		}
 		[Fact, AutoInitShutdown]
-		public void TestTreeViewColor()
+		public void TestTreeViewColor ()
 		{
-			var tv = new TreeView{Width = 20,Height = 10};
+			var tv = new TreeView { Width = 20, Height = 10 };
 
-			var n1 = new TreeNode("normal");
-			var n1_1 = new TreeNode("pink");
-			var n1_2 = new TreeNode("normal");
-			n1.Children.Add(n1_1);
-			n1.Children.Add(n1_2);
+			var n1 = new TreeNode ("normal");
+			var n1_1 = new TreeNode ("pink");
+			var n1_2 = new TreeNode ("normal");
+			n1.Children.Add (n1_1);
+			n1.Children.Add (n1_2);
 
-			var n2 = new TreeNode("pink");
-			tv.AddObject(n1);
-			tv.AddObject(n2);
-			tv.Expand(n1);
+			var n2 = new TreeNode ("pink");
+			tv.AddObject (n1);
+			tv.AddObject (n2);
+			tv.Expand (n1);
 
-			var pink = new Attribute(Color.Magenta,Color.Black);
-			var hotpink = new Attribute(Color.BrightMagenta,Color.Black);
+			var pink = new Attribute (Color.Magenta, Color.Black);
+			var hotpink = new Attribute (Color.BrightMagenta, Color.Black);
 
-			tv.ColorScheme = new ColorScheme();
-			tv.Redraw(tv.Bounds);
+			tv.ColorScheme = new ColorScheme ();
+			tv.Redraw (tv.Bounds);
 
 			// Normal drawing of the tree view
 			TestHelpers.AssertDriverContentsAre(
@@ -866,7 +866,7 @@ namespace Terminal.Gui.Views {
 │ ├─pink
 │ └─normal
 └─pink
-",output);
+", output);
 			// Should all be the same color
 			TestHelpers.AssertDriverColorsAre(
 @"00000000
@@ -874,30 +874,29 @@ namespace Terminal.Gui.Views {
 0000000000
 000000
 ",
-				new []{tv.ColorScheme.Normal,pink});
+				new [] { tv.ColorScheme.Normal, pink });
 
 			// create a new color scheme
-			var pinkScheme = new ColorScheme
-			{
+			var pinkScheme = new ColorScheme {
 				Normal = pink,
 				Focus = hotpink
 			};
 
 			// and a delegate that uses the pink color scheme 
 			// for nodes "pink"
-			tv.ColorGetter = (n)=> n.Text.Equals("pink") ? pinkScheme : null;
+			tv.ColorGetter = (n) => n.Text.Equals ("pink") ? pinkScheme : null;
 
 			// redraw now that the custom color
 			// delegate is registered
-			tv.Redraw(tv.Bounds);
-	
+			tv.Redraw (tv.Bounds);
+
 			// Same text
 			TestHelpers.AssertDriverContentsAre(
 @"├-normal
 │ ├─pink
 │ └─normal
 └─pink
-",output);
+", output);
 			// but now the item (only not lines) appear
 			// in pink when they are the word "pink"
 			TestHelpers.AssertDriverColorsAre(
@@ -906,7 +905,32 @@ namespace Terminal.Gui.Views {
 0000000000
 001111
 ",
-				new []{tv.ColorScheme.Normal,pink});
+				new [] { tv.ColorScheme.Normal, pink });
+		}
+
+		[Fact, AutoInitShutdown]
+		public void DesiredCursorVisibility_MultiSelect ()
+		{
+			var tv = new TreeView { Width = 20, Height = 10 };
+
+			var n1 = new TreeNode ("normal");
+			var n2 = new TreeNode ("pink");
+			tv.AddObject (n1);
+			tv.AddObject (n2);
+
+			Application.Top.Add (tv);
+			Application.Begin (Application.Top);
+
+			Assert.True (tv.MultiSelect);
+			Assert.True (tv.HasFocus);
+			Assert.Equal (CursorVisibility.Invisible, tv.DesiredCursorVisibility);
+
+			tv.SelectAll ();
+			tv.DesiredCursorVisibility = CursorVisibility.Default;
+			Application.Refresh ();
+			Application.Driver.GetCursorVisibility (out CursorVisibility visibility);
+			Assert.Equal (CursorVisibility.Default, tv.DesiredCursorVisibility);
+			Assert.Equal (CursorVisibility.Default, visibility);
 		}
 
 		/// <summary>

+ 1 - 1
UnitTests/UnitTests.csproj

@@ -26,7 +26,7 @@
       <PrivateAssets>all</PrivateAssets>
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
     </PackageReference>
-    <PackageReference Include="coverlet.collector" Version="3.1.2">
+    <PackageReference Include="coverlet.collector" Version="3.2.0">
       <PrivateAssets>all</PrivateAssets>
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
     </PackageReference>