소스 검색

Fixes view to screen relative on the context menu.

BDisp 3 년 전
부모
커밋
04f9817023
3개의 변경된 파일200개의 추가작업 그리고 26개의 파일을 삭제
  1. 11 4
      Terminal.Gui/Core/ContextMenu.cs
  2. 12 3
      UICatalog/Scenarios/ContextMenus.cs
  3. 177 19
      UnitTests/ContextMenuTests.cs

+ 11 - 4
Terminal.Gui/Core/ContextMenu.cs

@@ -22,7 +22,7 @@ namespace Terminal.Gui {
 		/// <param name="host">The host view.</param>
 		/// <param name="menuItems">The menu items.</param>
 		public ContextMenu (View host, MenuBarItem menuItems) :
-			this (host.Frame.X + 1, host.Frame.Bottom, menuItems)
+			this (host.Frame.X, host.Frame.Y, menuItems)
 		{
 			Host = host;
 		}
@@ -75,8 +75,13 @@ namespace Terminal.Gui {
 			container.Resized += Container_Resized;
 			var frame = container.Frame;
 			var position = Position;
-			if (Host != null && position != new Point (Host.Frame.X + 1, Host.Frame.Bottom)) {
-				Position = position = new Point (Host.Frame.X + 1, Host.Frame.Bottom);
+			if (Host != null) {
+				Host.ViewToScreen (container.Frame.X, container.Frame.Y, out int x, out int y);
+				var pos = new Point (x, y);
+				pos.Y += Host.Frame.Height - 1;
+				if (position != pos) {
+					Position = position = pos;
+				}
 			}
 			var rect = Menu.MakeFrame (position.X, position.Y, MenuItens.Children);
 			if (rect.Right >= frame.Right) {
@@ -93,7 +98,9 @@ namespace Terminal.Gui {
 					if (Host == null) {
 						position.Y = frame.Bottom - rect.Height - 1;
 					} else {
-						position.Y = Host.Frame.Y - rect.Height;
+						Host.ViewToScreen (container.Frame.X, container.Frame.Y, out int x, out int y);
+						var pos = new Point (x, y);
+						position.Y = pos.Y - rect.Height - 1;
 					}
 				} else if (ForceMinimumPosToZero) {
 					position.Y = 0;

+ 12 - 3
UICatalog/Scenarios/ContextMenus.cs

@@ -59,7 +59,7 @@ namespace UICatalog.Scenarios {
 			Point mousePos = default;
 
 			Win.KeyPress += (e) => {
-				if (e.KeyEvent.Key == (Key.Space | Key.CtrlMask) && !ContextMenu.IsShow) {
+				if (e.KeyEvent.Key == (Key.Space | Key.CtrlMask)) {
 					ShowContextMenu (mousePos.X, mousePos.Y);
 					e.Handled = true;
 				}
@@ -70,12 +70,21 @@ namespace UICatalog.Scenarios {
 					ShowContextMenu (e.MouseEvent.X, e.MouseEvent.Y);
 					e.Handled = true;
 				}
-				mousePos = new Point (e.MouseEvent.X, e.MouseEvent.Y);
 			};
 
+			Application.RootMouseEvent += Application_RootMouseEvent;
+
+			void Application_RootMouseEvent (MouseEvent me)
+			{
+				mousePos = new Point (me.X, me.Y);
+			}
+
 			Win.WantMousePositionReports = true;
 
-			Top.Closed += (_) => Thread.CurrentThread.CurrentUICulture = new CultureInfo ("en-US");
+			Top.Closed += (_) => {
+				Thread.CurrentThread.CurrentUICulture = new CultureInfo ("en-US");
+				Application.RootMouseEvent -= Application_RootMouseEvent;
+			};
 		}
 
 		private void ShowContextMenu (int x, int y)

+ 177 - 19
UnitTests/ContextMenuTests.cs

@@ -42,7 +42,7 @@ namespace Terminal.Gui.Core {
 					new MenuItem ("Two", "", null)
 				})
 			);
-			Assert.Equal (new Point (6, 10), cm.Position);
+			Assert.Equal (new Point (5, 10), cm.Position);
 			Assert.Equal (2, cm.MenuItens.Children.Length);
 			Assert.NotNull (cm.Host);
 		}
@@ -279,64 +279,100 @@ namespace Terminal.Gui.Core {
 		[Fact, AutoInitShutdown]
 		public void Show_Ensures_Display_Inside_The_Container_Without_Overlap_The_Host ()
 		{
-			var cm = new ContextMenu (new View () { X = 69, Y = 24, Width = 10, Height = 1 },
+			var view = new View ("View") {
+				X = Pos.AnchorEnd (10),
+				Y = Pos.AnchorEnd (1),
+				Width = 10,
+				Height = 1
+			};
+			var cm = new ContextMenu (view,
 				new MenuBarItem (new MenuItem [] {
 					new MenuItem ("One", "", null),
 					new MenuItem ("Two", "", null)
 				})
 			);
 
-			Assert.Equal (new Point (70, 25), cm.Position);
+			Application.Top.Add (view);
+			Application.Begin (Application.Top);
+
+			Assert.Equal (new Rect (70, 24, 10, 1), view.Frame);
+			Assert.Equal (new Point (0, 0), cm.Position);
 
 			cm.Show ();
-			Assert.Equal (new Point (70, 25), cm.Position);
-			Application.Begin (Application.Top);
+			Assert.Equal (new Point (70, 24), cm.Position);
+			Application.Top.Redraw (Application.Top.Bounds);
 
 			var expected = @"
                                                                       ┌──────┐
                                                                       │ One  │
                                                                       │ Two  │
                                                                       └──────┘
+                                                                      View
 ";
 
 			var pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
-			Assert.Equal (new Rect (70, 21, 78, 4), pos);
+			Assert.Equal (new Rect (70, 20, 78, 5), pos);
 
 			cm.Hide ();
-			Assert.Equal (new Point (70, 25), cm.Position);
+			Assert.Equal (new Point (70, 24), cm.Position);
 		}
 
 		[Fact, AutoInitShutdown]
 		public void Show_Display_Below_The_Bottom_Host_If_Has_Enough_Space ()
 		{
-			var cm = new ContextMenu (new View () { X = 10, Y = 5, Width = 10, Height = 1 },
+			var view = new View ("View") { X = 10, Y = 5, Width = 10, Height = 1 };
+			var cm = new ContextMenu (view,
 				new MenuBarItem (new MenuItem [] {
 					new MenuItem ("One", "", null),
 					new MenuItem ("Two", "", null)
 				})
 			);
 
-			Assert.Equal (new Point (11, 6), cm.Position);
+			Application.Top.Add (view);
+			Application.Begin (Application.Top);
 
-			cm.Host.X = 5;
-			cm.Host.Y = 10;
+			Assert.Equal (new Point (10, 5), cm.Position);
 
 			cm.Show ();
-			Assert.Equal (new Point (6, 11), cm.Position);
-			Application.Begin (Application.Top);
+			Application.Top.Redraw (Application.Top.Bounds);
+			Assert.Equal (new Point (10, 5), cm.Position);
 
 			var expected = @"
-      ┌──────┐
-      │ One  │
-      │ Two  │
-      └──────┘
+          View
+          ┌──────┐
+          │ One  │
+          │ Two  │
+          └──────┘
 ";
 
 			var pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
-			Assert.Equal (new Rect (6, 12, 14, 4), pos);
+			Assert.Equal (new Rect (10, 5, 18, 5), pos);
+
+			cm.Hide ();
+			Assert.Equal (new Point (10, 5), cm.Position);
+			cm.Host.X = 5;
+			cm.Host.Y = 10;
+			cm.Host.Height = 3;
+
+			cm.Show ();
+			Application.Top.Redraw (Application.Top.Bounds);
+			Assert.Equal (new Point (5, 12), cm.Position);
+
+			expected = @"
+     View
+
+
+     ┌──────┐
+     │ One  │
+     │ Two  │
+     └──────┘
+";
+
+			pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
+			Assert.Equal (new Rect (5, 10, 13, 7), pos);
 
 			cm.Hide ();
-			Assert.Equal (new Point (6, 11), cm.Position);
+			Assert.Equal (new Point (5, 12), cm.Position);
 		}
 
 		[Fact, AutoInitShutdown]
@@ -515,5 +551,127 @@ namespace Terminal.Gui.Core {
 			Assert.Equal (menu, Application.mouseGrabView);
 			Assert.True (menu.IsMenuOpen);
 		}
+
+		[Fact, AutoInitShutdown]
+		public void ContextMenu_On_Toplevel_With_A_MenuBar_TextField_StatusBar ()
+		{
+			var menu = new MenuBar (new MenuBarItem [] {
+				new MenuBarItem ("File", "", null),
+				new MenuBarItem ("Edit", "", null)
+			});
+
+			var label = new Label ("Label:") {
+				X = 2,
+				Y = 3
+			};
+
+			var tf = new TextField ("TextField") {
+				X = Pos.Right (label) + 1,
+				Y = Pos.Top (label),
+				Width = 20
+			};
+
+			var statusBar = new StatusBar (new StatusItem [] {
+				new StatusItem(Key.F1, "~F1~ Help", null),
+				new StatusItem(Key.CtrlMask | Key.Q, "~^Q~ Quit", null)
+			});
+
+			Application.Top.Add (menu, label, tf, statusBar);
+			Application.Begin (Application.Top);
+			((FakeDriver)Application.Driver).SetBufferSize (45, 17);
+
+			Assert.Equal (new Rect (9, 3, 20, 1), tf.Frame);
+			Assert.True (tf.HasFocus);
+
+			tf.ContextMenu.Show ();
+			Assert.True (ContextMenu.IsShow);
+			Assert.Equal (new Point (9, 3), tf.ContextMenu.Position);
+			Application.Top.Redraw (Application.Top.Bounds);
+			var expected = @"
+  File   Edit
+
+
+  Label: TextField
+         ┌────────────────────────────┐
+         │ Select All          Ctrl+T │
+         │ Delete All    Ctrl+Shift+D │
+         │ Copy                Ctrl+C │
+         │ Cut                 Ctrl+X │
+         │ Paste               Ctrl+V │
+         │ Undo                Ctrl+Z │
+         │ Redo                Ctrl+Y │
+         └────────────────────────────┘
+
+
+
+ F1 Help │ ^Q Quit
+";
+
+			var pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
+			Assert.Equal (new Rect (2, 0, 39, 17), pos);
+		}
+
+		[Fact, AutoInitShutdown]
+		public void ContextMenu_On_Toplevel_With_A_MenuBar_Window_TextField_StatusBar ()
+		{
+			var menu = new MenuBar (new MenuBarItem [] {
+				new MenuBarItem ("File", "", null),
+				new MenuBarItem ("Edit", "", null)
+			});
+
+			var label = new Label ("Label:") {
+				X = 2,
+				Y = 3
+			};
+
+			var tf = new TextField ("TextField") {
+				X = Pos.Right (label) + 1,
+				Y = Pos.Top (label),
+				Width = 20
+			};
+
+			var win = new Window ("Window");
+			win.Add (label, tf);
+
+			var statusBar = new StatusBar (new StatusItem [] {
+				new StatusItem(Key.F1, "~F1~ Help", null),
+				new StatusItem(Key.CtrlMask | Key.Q, "~^Q~ Quit", null)
+			});
+
+			Application.Top.Add (menu, win, statusBar);
+			Application.Begin (Application.Top);
+			((FakeDriver)Application.Driver).SetBufferSize (45, 17);
+
+
+			Assert.Equal (new Rect (9, 3, 20, 1), tf.Frame);
+			Assert.True (tf.HasFocus);
+
+			tf.ContextMenu.Show ();
+			Assert.True (ContextMenu.IsShow);
+			Assert.Equal (new Point (10, 5), tf.ContextMenu.Position);
+			Application.Top.Redraw (Application.Top.Bounds);
+			var expected = @"
+  File   Edit
+┌ Window ───────────────────────────────────┐
+│                                           │
+│                                           │
+│                                           │
+│  Label: TextField                         │
+│         ┌────────────────────────────┐    │
+│         │ Select All          Ctrl+T │    │
+│         │ Delete All    Ctrl+Shift+D │    │
+│         │ Copy                Ctrl+C │    │
+│         │ Cut                 Ctrl+X │    │
+│         │ Paste               Ctrl+V │    │
+│         │ Undo                Ctrl+Z │    │
+│         │ Redo                Ctrl+Y │    │
+│         └────────────────────────────┘    │
+└───────────────────────────────────────────┘
+ F1 Help │ ^Q Quit
+";
+
+			var pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
+			Assert.Equal (new Rect (2, 0, 45, 17), pos);
+		}
 	}
 }