Explorar o código

Merge branch 'develop' of tig:gui-cs/Terminal.Gui into develop

Tig hai 1 ano
pai
achega
a3d984ac34

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

@@ -31,7 +31,7 @@ jobs:
       continue-on-error: false
 
     - name: Setup Pages
-      uses: actions/configure-pages@v4
+      uses: actions/configure-pages@v5
       
     - name: Upload artifact
       uses: actions/upload-pages-artifact@v2

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

@@ -19,13 +19,13 @@ jobs:
         fetch-depth: 0 # fetch-depth is needed for GitVersion
 
     - name: Install GitVersion 
-      uses: gittools/actions/gitversion/setup@v0
+      uses: gittools/actions/gitversion/setup@v1
       with:
           versionSpec: '5.x'
           includePrerelease: true
 
     - name: Determine Version
-      uses: gittools/actions/gitversion/execute@v0
+      uses: gittools/actions/gitversion/execute@v1
       with:
         useConfigFile: true
         #additionalArguments: /b develop

+ 1 - 1
ReactiveExample/ReactiveExample.csproj

@@ -11,7 +11,7 @@
   </PropertyGroup>
   <ItemGroup>
     <PackageReference Include="ReactiveUI.Fody" Version="19.5.41" />
-    <PackageReference Include="ReactiveUI" Version="19.5.41" />
+    <PackageReference Include="ReactiveUI" Version="20.0.1" />
     <PackageReference Include="ReactiveMarbles.ObservableEvents.SourceGenerator" Version="1.3.1" PrivateAssets="all" />
   </ItemGroup>
   <ItemGroup>

+ 6 - 2
Showcase.md

@@ -16,10 +16,14 @@
   ![PoshDotnetDumpAnalyzerViewer.png](docfx/images/PoshDotnetDumpAnalyzerViewer.png)  
 * **[TerminalGuiDesigner](https://github.com/tznind/TerminalGuiDesigner)** - Cross platform view designer for building Terminal.Gui applications.
-  ![TerminalGuiDesigner.gif](docfx/images/TerminalGuiDesigner.gif)  
+  ![TerminalGuiDesigner.gif](docfx/images/TerminalGuiDesigner.gif)
+
+* **[Capital and Cargo](https://github.com/dhorions/Capital-and-Cargo)** - A retro console game where you buy, sell, produce and transport goods built with Terminal.Gui
+ ![image](https://github.com/gui-cs/Terminal.Gui/assets/1682004/ed89f3d6-020f-4a8a-ae18-e057514f4c43)
+
   
 # Examples #
 
 * **[C# Example](https://github.com/gui-cs/Terminal.Gui/tree/master/Example)** - Run `dotnet run` in the `Example` directory to run the C# Example.
 * **[F# Example](https://github.com/gui-cs/Terminal.Gui/tree/master/FSharpExample)** - An example showing how to build a Terminal.Gui app using F#.
-* **[Reactive Example](https://github.com/gui-cs/Terminal.Gui/tree/master/ReactiveExample)** - A sample app that shows how to use `System.Reactive` and `ReactiveUI` with `Terminal.Gui`. The app uses the MVVM architecture that may seem familiar to folks coming from WPF, Xamarin Forms, UWP, Avalonia, or Windows Forms. In this app, we implement the data bindings using ReactiveUI `WhenAnyValue` syntax and [Pharmacist](https://github.com/reactiveui/pharmacist) — a tool that converts all events in a NuGet package into observable wrappers. 
+* **[Reactive Example](https://github.com/gui-cs/Terminal.Gui/tree/master/ReactiveExample)** - A sample app that shows how to use `System.Reactive` and `ReactiveUI` with `Terminal.Gui`. The app uses the MVVM architecture that may seem familiar to folks coming from WPF, Xamarin Forms, UWP, Avalonia, or Windows Forms. In this app, we implement the data bindings using ReactiveUI `WhenAnyValue` syntax and [Pharmacist](https://github.com/reactiveui/pharmacist) — a tool that converts all events in a NuGet package into observable wrappers. 

+ 1 - 3
Terminal.Gui/Core/Application.cs

@@ -1040,9 +1040,7 @@ namespace Terminal.Gui {
 			if (refreshDriver) {
 				MdiTop?.OnChildLoaded (toplevel);
 				toplevel.OnLoaded ();
-				Redraw (toplevel);
-				toplevel.PositionCursor ();
-				Driver.Refresh ();
+				Refresh ();
 			}
 
 			NotifyNewRunState?.Invoke (rs);

+ 4 - 4
Terminal.Gui/Core/Event.cs

@@ -753,13 +753,13 @@ namespace Terminal.Gui {
 		/// </summary>
 		WheeledDown = unchecked((int)0x20000000),
 		/// <summary>
-		/// Vertical button wheeled up while pressing ButtonShift.
+		/// Vertical button wheeled up while pressing ButtonCtrl.
 		/// </summary>
-		WheeledLeft = ButtonShift | WheeledUp,
+		WheeledLeft = ButtonCtrl | WheeledUp,
 		/// <summary>
-		/// Vertical button wheeled down while pressing ButtonShift.
+		/// Vertical button wheeled down while pressing ButtonCtrl.
 		/// </summary>
-		WheeledRight = ButtonShift | WheeledDown,
+		WheeledRight = ButtonCtrl | WheeledDown,
 		/// <summary>
 		/// Mask that captures all the events.
 		/// </summary>

+ 9 - 4
Terminal.Gui/Core/View.cs

@@ -282,7 +282,7 @@ namespace Terminal.Gui {
 				} else if (SuperView?.tabIndexes == null || SuperView?.tabIndexes.Count == 1) {
 					tabIndex = 0;
 					return;
-				} else if (tabIndex == value) {
+				} else if (tabIndex == value && TabIndexes.IndexOf (this) == value) {
 					return;
 				}
 				tabIndex = value > SuperView.tabIndexes.Count - 1 ? SuperView.tabIndexes.Count - 1 : value < 0 ? 0 : value;
@@ -2894,9 +2894,14 @@ namespace Terminal.Gui {
 				return false;
 			}
 
-			var args = new MouseEventArgs (mouseEvent);
-			if (OnMouseClick (args))
-				return true;
+			if ((mouseEvent.Flags & MouseFlags.Button1Clicked) != 0 || (mouseEvent.Flags & MouseFlags.Button2Clicked) != 0
+				|| (mouseEvent.Flags & MouseFlags.Button3Clicked) != 0 || (mouseEvent.Flags & MouseFlags.Button4Clicked) != 0) {
+
+				var args = new MouseEventArgs (mouseEvent);
+				if (OnMouseClick (args)) {
+					return true;
+				}
+			}
 			if (MouseEvent (mouseEvent))
 				return true;
 

+ 1 - 1
Terminal.Gui/Views/ComboBox.cs

@@ -792,7 +792,7 @@ namespace Terminal.Gui {
 			listview.SetSource (searchset);
 			listview.Height = CalculatetHeight ();
 
-			if (Subviews.Count > 0) {
+			if (HasFocus && Subviews.Count > 0) {
 				search.SetFocus ();
 			}
 		}

+ 4 - 5
Terminal.Gui/Views/ListView.cs

@@ -802,8 +802,6 @@ namespace Terminal.Gui {
 			selected = top + me.Y;
 			if (AllowsAll ()) {
 				Source.SetMark (SelectedItem, !Source.IsMarked (SelectedItem));
-				SetNeedsDisplay ();
-				return true;
 			}
 			OnSelectedChanged ();
 			SetNeedsDisplay ();
@@ -866,7 +864,8 @@ namespace Terminal.Gui {
 
 		void RenderUstr (ConsoleDriver driver, ustring ustr, int col, int line, int width, int start = 0)
 		{
-			var u = TextFormatter.ClipAndJustify (ustr, width + start, TextAlignment.Left);
+			ustring str = start > ustr.ConsoleWidth ? string.Empty : ustr.Substring (Math.Min (start, ustr.ToRunes ().Length - 1));
+			ustring u = TextFormatter.ClipAndJustify (str, width, TextAlignment.Left);
 			driver.AddStr (u);
 			width -= TextFormatter.GetTextWidth (u);
 			while (width-- + start > 0) {
@@ -877,8 +876,8 @@ namespace Terminal.Gui {
 		/// <inheritdoc/>
 		public void Render (ListView container, ConsoleDriver driver, bool marked, int item, int col, int line, int width, int start = 0)
 		{
-			var savedClip = container.ClipToBounds();
-			container.Move (col - start, line);
+			var savedClip = container.ClipToBounds ();
+			container.Move (Math.Max (col - start, 0), line);
 			var t = src? [item];
 			if (t == null) {
 				RenderUstr (driver, ustring.Make (""), col, line, width);

+ 1 - 1
Terminal.Gui/Views/ScrollView.cs

@@ -349,7 +349,7 @@ namespace Terminal.Gui {
 		{
 			Driver.SetAttribute (GetNormalColor ());
 			SetViewsNeedsDisplay ();
-			//Clear ();
+			Clear ();
 
 			var savedClip = ClipToBounds ();
 			OnDrawContent (new Rect (ContentOffset,

+ 4 - 0
Terminal.Gui/Windows/Wizard.cs

@@ -773,6 +773,10 @@ namespace Terminal.Gui {
 			var oldStep = currentStep;
 			currentStep = newStep;
 
+			if (currentStep is null) {
+				return false;
+			}
+
 			UpdateButtonsAndTitle ();
 
 			// Set focus to the nav buttons

+ 5 - 1
Terminal.sln.DotSettings

@@ -112,6 +112,9 @@
 	<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Constants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
 	<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
 	<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
+	<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=4a98fdf6_002D7d98_002D4f5a_002Dafeb_002Dea44ad98c70c/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Instance" AccessRightKinds="Private" Description="Instance fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="FIELD" /&gt;&lt;Kind Name="READONLY_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;&lt;/Policy&gt;</s:String>
+	<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=669e5282_002Dfb4b_002D4e90_002D91e7_002D07d269d04b60/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Constant fields (not private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="CONSTANT_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;</s:String>
+	<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=f9fce829_002De6f4_002D4cb2_002D80f1_002D5497c44f51df/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;&lt;/Policy&gt;</s:String>
 	<s:Boolean x:Key="/Default/Environment/InjectedLayers/FileInjectedLayer/=CAF4ECB3AC41AE43BD233D613AC1562C/@KeyIndexDefined">True</s:Boolean>
 	<s:String x:Key="/Default/Environment/InjectedLayers/FileInjectedLayer/=CAF4ECB3AC41AE43BD233D613AC1562C/AbsolutePath/@EntryValue">Terminal.sln.DotSettings</s:String>
 	<s:String x:Key="/Default/Environment/InjectedLayers/FileInjectedLayer/=CAF4ECB3AC41AE43BD233D613AC1562C/RelativePath/@EntryValue"></s:String>
@@ -125,4 +128,5 @@
 	<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
 	<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
 	<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
-	<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
+	<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
+	<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

+ 2 - 2
UICatalog/Scenarios/ListViewWithSelection.cs

@@ -79,9 +79,9 @@ namespace UICatalog.Scenarios {
 			};
 
 			_listView.DrawContent += (e) => {
-				_scrollBar.Size = _listView.Source.Count - 1;
+				_scrollBar.Size = _listView.Source.Count;
 				_scrollBar.Position = _listView.TopItem;
-				_scrollBar.OtherScrollBarView.Size = _listView.Maxlength - 1;
+				_scrollBar.OtherScrollBarView.Size = _listView.Maxlength;
 				_scrollBar.OtherScrollBarView.Position = _listView.LeftItem;
 				_scrollBar.Refresh ();
 			};

+ 3 - 3
UICatalog/UICatalog.csproj

@@ -20,9 +20,9 @@
     <None Update="./Scenarios/Spinning_globe_dark_small.gif" CopyToOutputDirectory="PreserveNewest" />
   </ItemGroup>
   <ItemGroup>
-    <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.6" />
-    <PackageReference Include="SixLabors.ImageSharp" Version="3.1.2" />
-    <PackageReference Include="CsvHelper" Version="31.0.0" />
+    <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.20.1" />
+    <PackageReference Include="SixLabors.ImageSharp" Version="3.1.4" />
+    <PackageReference Include="CsvHelper" Version="32.0.2" />
     <PackageReference Include="Microsoft.DotNet.PlatformAbstractions" Version="3.1.6" />
   </ItemGroup>
   <ItemGroup>

+ 4 - 4
UnitTests/UnitTests.csproj

@@ -19,14 +19,14 @@
   </PropertyGroup>
   <ItemGroup>
     <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
-    <PackageReference Include="ReportGenerator" Version="5.2.2" />
+    <PackageReference Include="ReportGenerator" Version="5.2.5" />
     <PackageReference Include="System.Collections" Version="4.3.0" />
-    <PackageReference Include="xunit" Version="2.7.0" />
-    <PackageReference Include="xunit.runner.visualstudio" Version="2.5.7">
+    <PackageReference Include="xunit" Version="2.8.0" />
+    <PackageReference Include="xunit.runner.visualstudio" Version="2.8.0">
       <PrivateAssets>all</PrivateAssets>
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
     </PackageReference>
-    <PackageReference Include="coverlet.collector" Version="6.0.1">
+    <PackageReference Include="coverlet.collector" Version="6.0.2">
       <PrivateAssets>all</PrivateAssets>
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
     </PackageReference>

+ 19 - 0
UnitTests/Views/ListViewTests.cs

@@ -545,5 +545,24 @@ Item 6", output);
  tem 3
  tem 4", output);
 		}
+
+		[Fact]
+		public void SelectedItemChanged_Event_Is_Also_Raised_With_AllowsMarking_True_By_Keyboard_Or_Mouse ()
+		{
+			var itemChanged = 0;
+			var lv = new ListView (new List<string> () { "Item1", "Item2", "Item3" }) { Width = 5, Height = 3, AllowsMarking = true };
+			lv.SelectedItemChanged += (e) => itemChanged = e.Item;
+
+			Assert.Equal (0, lv.SelectedItem);
+			Assert.Equal (lv.SelectedItem, itemChanged);
+
+			Assert.True (lv.ProcessKey (new KeyEvent (Key.CursorDown, new KeyModifiers())));
+			Assert.Equal (1, lv.SelectedItem);
+			Assert.Equal (lv.SelectedItem, itemChanged);
+
+			Assert.True (lv.MouseEvent (new MouseEvent(){ X = 0, Y = 2, Flags = MouseFlags.Button1Clicked}));
+			Assert.Equal (2, lv.SelectedItem);
+			Assert.Equal (lv.SelectedItem, itemChanged);
+		}
 	}
 }

+ 93 - 0
UnitTests/Views/ViewTests.cs

@@ -371,6 +371,79 @@ namespace Terminal.Gui.ViewTests {
 			Assert.True (r.TabIndexes.IndexOf (v1) == 1);
 		}
 
+		[Fact]
+		public void TabIndex_Invert_Order ()
+		{
+			var r = new View ();
+			var v1 = new View () { Id = "1", CanFocus = true };
+			var v2 = new View () { Id = "2", CanFocus = true };
+			var v3 = new View () { Id = "3", CanFocus = true };
+
+			r.Add (v1, v2, v3);
+
+			v1.TabIndex = 2;
+			v2.TabIndex = 1;
+			v3.TabIndex = 0;
+			Assert.True (r.TabIndexes.IndexOf (v1) == 2);
+			Assert.True (r.TabIndexes.IndexOf (v2) == 1);
+			Assert.True (r.TabIndexes.IndexOf (v3) == 0);
+
+			Assert.True (r.Subviews.IndexOf (v1) == 0);
+			Assert.True (r.Subviews.IndexOf (v2) == 1);
+			Assert.True (r.Subviews.IndexOf (v3) == 2);
+		}
+
+		[Fact]
+		public void TabIndex_Invert_Order_Added_One_By_One_Does_Not_Do_What_Is_Expected ()
+		{
+			var r = new View ();
+			var v1 = new View () { Id = "1", CanFocus = true };
+			r.Add (v1);
+			v1.TabIndex = 2;
+			var v2 = new View () { Id = "2", CanFocus = true };
+			r.Add (v2);
+			v2.TabIndex = 1;
+			var v3 = new View () { Id = "3", CanFocus = true };
+			r.Add (v3);
+			v3.TabIndex = 0;
+
+			Assert.False (r.TabIndexes.IndexOf (v1) == 2);
+			Assert.True (r.TabIndexes.IndexOf (v1) == 1);
+			Assert.False (r.TabIndexes.IndexOf (v2) == 1);
+			Assert.True (r.TabIndexes.IndexOf (v2) == 2);
+			// Only the last is in the expected index
+			Assert.True (r.TabIndexes.IndexOf (v3) == 0);
+
+			Assert.True (r.Subviews.IndexOf (v1) == 0);
+			Assert.True (r.Subviews.IndexOf (v2) == 1);
+			Assert.True (r.Subviews.IndexOf (v3) == 2);
+		}
+
+		[Fact]
+		public void TabIndex_Invert_Order_Mixed ()
+		{
+			var r = new View ();
+			var vl1 = new View () { Id = "vl1" };
+			var v1 = new View () { Id = "v1", CanFocus = true };
+			var vl2 = new View () { Id = "vl2" };
+			var v2 = new View () { Id = "v2", CanFocus = true };
+			var vl3 = new View () { Id = "vl3" };
+			var v3 = new View () { Id = "v3", CanFocus = true };
+
+			r.Add (vl1, v1, vl2, v2, vl3, v3);
+
+			v1.TabIndex = 2;
+			v2.TabIndex = 1;
+			v3.TabIndex = 0;
+			Assert.True (r.TabIndexes.IndexOf (v1) == 4);
+			Assert.True (r.TabIndexes.IndexOf (v2) == 2);
+			Assert.True (r.TabIndexes.IndexOf (v3) == 0);
+
+			Assert.True (r.Subviews.IndexOf (v1) == 1);
+			Assert.True (r.Subviews.IndexOf (v2) == 3);
+			Assert.True (r.Subviews.IndexOf (v3) == 5);
+		}
+
 		[Fact]
 		public void TabStop_And_CanFocus_Are_All_True ()
 		{
@@ -1173,6 +1246,10 @@ namespace Terminal.Gui.ViewTests {
 
 			Application.Run ();
 
+			// Ensures cleaning any keystroke.
+			// This was conflicting with the TestVKPacket unit test
+			Console.MockKeyPresses.Clear ();
+
 			// Shutdown must be called to safely clean up Application if Init has been called
 			Application.Shutdown ();
 		}
@@ -4581,5 +4658,21 @@ Test", output);
 011110
 000000", new Attribute [] { Colors.TopLevel.Normal, Colors.TopLevel.Focus });
 		}
+
+		[Theory]
+		[InlineData (MouseFlags.Button1Pressed, MouseFlags.Button1Released, MouseFlags.Button1Clicked)]
+		[InlineData (MouseFlags.Button1Pressed | MouseFlags.ButtonCtrl, MouseFlags.Button1Released | MouseFlags.ButtonCtrl, MouseFlags.Button1Clicked | MouseFlags.ButtonCtrl)]
+		public void OnMouseClick_Is_Only_Raised_Once (MouseFlags pressed, MouseFlags released, MouseFlags clicked)
+		{
+			var mouseClicks = 0;
+			var view = new View ();
+			view.MouseClick += (_) => mouseClicks++;
+
+			view.OnMouseEvent (new MouseEvent () { Flags = pressed });
+			view.OnMouseEvent (new MouseEvent () { Flags = released });
+			view.OnMouseEvent (new MouseEvent () { Flags = clicked });
+
+			Assert.Equal (1, mouseClicks);
+		}
 	}
 }