Selaa lähdekoodia

Subscribing DrawContentComplete on the Application which allow draw over modal views.

BDisp 2 vuotta sitten
vanhempi
commit
4843fd0205

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

@@ -277,14 +277,6 @@ namespace Terminal.Gui {
 		/// </remarks>
 		public static Action Iteration;
 
-		/// <summary>
-		///   This event is raised on each iteration of the <see cref="MainLoop"/> after all processes are completed.
-		/// </summary>
-		/// <remarks>
-		///   See also <see cref="Timeout"/>
-		/// </remarks>
-		public static Action IterationComplete;
-
 		/// <summary>
 		/// Returns a rectangle that is centered in the screen for the provided size.
 		/// </summary>
@@ -1290,6 +1282,7 @@ namespace Terminal.Gui {
 			if (!state.Toplevel.NeedDisplay.IsEmpty || state.Toplevel.ChildNeedsDisplay || state.Toplevel.LayoutNeeded
 				|| MdiChildNeedsDisplay ()) {
 				state.Toplevel.Redraw (state.Toplevel.Bounds);
+				state.Toplevel.OnDrawContentComplete (state.Toplevel.Bounds);
 				if (DebugDrawBounds) {
 					DrawBounds (state.Toplevel);
 				}
@@ -1302,7 +1295,6 @@ namespace Terminal.Gui {
 				&& (!Top.NeedDisplay.IsEmpty || Top.ChildNeedsDisplay || Top.LayoutNeeded)) {
 				Top.Redraw (Top.Bounds);
 			}
-			IterationComplete?.Invoke ();
 		}
 
 		static void EnsureModalOrVisibleAlwaysOnTop (Toplevel toplevel)

+ 4 - 4
Terminal.Gui/Views/ContextMenu.cs

@@ -91,7 +91,7 @@ namespace Terminal.Gui {
 			if (menuBar != null) {
 				Hide ();
 			}
-			container = Application.Current;
+			container = Application.Top;
 			container.Closing += Container_Closing;
 			container.Resized += Container_Resized;
 			var frame = container.Frame;
@@ -162,7 +162,7 @@ namespace Terminal.Gui {
 		/// </summary>
 		public void Hide ()
 		{
-			menuBar.CleanUp ();
+			menuBar?.CleanUp ();
 			Dispose ();
 		}
 
@@ -194,7 +194,7 @@ namespace Terminal.Gui {
 			set {
 				var oldKey = key;
 				key = value;
-				KeyChanged?.Invoke (this, new KeyChangedEventArgs(oldKey,key));
+				KeyChanged?.Invoke (this, new KeyChangedEventArgs (oldKey, key));
 			}
 		}
 
@@ -206,7 +206,7 @@ namespace Terminal.Gui {
 			set {
 				var oldFlags = mouseFlags;
 				mouseFlags = value;
-				MouseFlagsChanged?.Invoke (this, new MouseFlagsChangedEventArgs(oldFlags,value));
+				MouseFlagsChanged?.Invoke (this, new MouseFlagsChangedEventArgs (oldFlags, value));
 			}
 		}
 

+ 36 - 36
Terminal.Gui/Views/Menu.cs

@@ -477,6 +477,10 @@ namespace Terminal.Gui {
 				WantMousePositionReports = host.WantMousePositionReports;
 			}
 
+			if (Application.Current != null) {
+				Application.Current.DrawContentComplete += Current_DrawContentComplete;
+			}
+
 			// Things this view knows how to do
 			AddCommand (Command.LineUp, () => MoveUp ());
 			AddCommand (Command.LineDown, () => MoveDown ());
@@ -511,9 +515,16 @@ namespace Terminal.Gui {
 			return GetNormalColor ();
 		}
 
-		// Draws the Menu, within the Frame
 		public override void Redraw (Rect bounds)
 		{
+		}
+
+		// Draws the Menu, within the Frame
+		private void Current_DrawContentComplete (object sender, DrawEventArgs e)
+		{
+			if (barItems.Children == null) {
+				return;
+			}
 			Driver.SetAttribute (GetNormalColor ());
 			DrawFrame (Bounds, padding: 0, fill: true);
 
@@ -905,6 +916,14 @@ namespace Terminal.Gui {
 
 			return base.OnEnter (view);
 		}
+
+		protected override void Dispose (bool disposing)
+		{
+			if (Application.Current != null) {
+				Application.Current.DrawContentComplete -= Current_DrawContentComplete;
+			}
+			base.Dispose (disposing);
+		}
 	}
 
 	/// <summary>
@@ -1322,31 +1341,25 @@ namespace Terminal.Gui {
 			switch (subMenu) {
 			case null:
 				// Open a submenu below a MenuBar
-				lastFocused = lastFocused ?? (SuperView == null ? Application.Current.MostFocused : SuperView.MostFocused);
+				lastFocused ??= (SuperView == null ? Application.Current.MostFocused : SuperView.MostFocused);
 				if (openSubMenu != null && !CloseMenu (false, true))
 					return;
 				if (openMenu != null) {
-					if (SuperView == null) {
-						Application.Current.Remove (openMenu);
-					} else {
-						SuperView.Remove (openMenu);
-					}
+					Application.Top.Remove (openMenu);
 					openMenu.Dispose ();
+					openMenu = null;
 				}
 
 				// This positions the submenu horizontally aligned with the first character of the
 				// menu it belongs to's text
 				for (int i = 0; i < index; i++)
 					pos += Menus [i].TitleLength + (Menus [i].Help.ConsoleWidth > 0 ? Menus [i].Help.ConsoleWidth + 2 : 0) + leftPadding + rightPadding;
-				openMenu = new Menu (this, Frame.X + pos, Frame.Y + 1, Menus [index]);
+				var locationOffset = SuperView == null ? new Point (0, 0) : new Point (SuperView.Frame.X, SuperView.Frame.Y);
+				openMenu = new Menu (this, Frame.X + pos + locationOffset.X, Frame.Y + 1 + locationOffset.Y, Menus [index]);
 				openCurrentMenu = openMenu;
 				openCurrentMenu.previousSubFocused = openMenu;
 
-				if (SuperView == null) {
-					Application.Current.Add (openMenu);
-				} else {
-					SuperView.Add (openMenu);
-				}
+				Application.Top.Add (openMenu);
 				openMenu.SetFocus ();
 				break;
 			default:
@@ -1368,17 +1381,14 @@ namespace Terminal.Gui {
 							mbi [j + 2] = subMenu.Children [j];
 						}
 						var newSubMenu = new MenuBarItem (mbi);
-						openCurrentMenu = new Menu (this, first.Frame.Left, first.Frame.Top, newSubMenu);
+						ViewToScreen (first.Frame.Left, first.Frame.Top, out int rx, out int ry);
+						openCurrentMenu = new Menu (this, rx, ry, newSubMenu);
 						last.Visible = false;
 						Application.GrabMouse (openCurrentMenu);
 					}
 					openCurrentMenu.previousSubFocused = last.previousSubFocused;
 					openSubMenu.Add (openCurrentMenu);
-					if (SuperView == null) {
-						Application.Current.Add (openCurrentMenu);
-					} else {
-						SuperView.Add (openCurrentMenu);
-					}
+					Application.Current.Add (openCurrentMenu);
 				}
 				selectedSub = openSubMenu.Count - 1;
 				if (selectedSub > -1 && SelectEnabledItem (openCurrentMenu.barItems.Children, openCurrentMenu.current, out openCurrentMenu.current)) {
@@ -1501,11 +1511,7 @@ namespace Terminal.Gui {
 			switch (isSubMenu) {
 			case false:
 				if (openMenu != null) {
-					if (SuperView == null) {
-						Application.Current.Remove (openMenu);
-					} else {
-						SuperView?.Remove (openMenu);
-					}
+					Application.Top.Remove (openMenu);
 				}
 				SetNeedsDisplay ();
 				if (previousFocused != null && previousFocused is Menu && openMenu != null && previousFocused.ToString () != openCurrentMenu.ToString ())
@@ -1564,11 +1570,7 @@ namespace Terminal.Gui {
 				openCurrentMenu.SetFocus ();
 				if (openSubMenu != null) {
 					menu = openSubMenu [i];
-					if (SuperView == null) {
-						Application.Current.Remove (menu);
-					} else {
-						SuperView.Remove (menu);
-					}
+					Application.Top.Remove (menu);
 					openSubMenu.Remove (menu);
 					menu.Dispose ();
 				}
@@ -1584,11 +1586,7 @@ namespace Terminal.Gui {
 		{
 			if (openSubMenu != null) {
 				foreach (var item in openSubMenu) {
-					if (SuperView == null) {
-						Application.Current.Remove (item);
-					} else {
-						SuperView.Remove (item);
-					}
+					Application.Top.Remove (item);
 					item.Dispose ();
 				}
 			}
@@ -1757,7 +1755,8 @@ namespace Terminal.Gui {
 			}
 
 			if (mi.IsTopLevel) {
-				var menu = new Menu (this, i, 0, mi);
+				ViewToScreen (i, 0, out int rx, out int ry);
+				var menu = new Menu (this, rx, ry, mi);
 				menu.Run (mi.Action);
 				menu.Dispose ();
 			} else {
@@ -1878,7 +1877,8 @@ namespace Terminal.Gui {
 					if (cx >= pos && cx < pos + leftPadding + Menus [i].TitleLength + Menus [i].Help.ConsoleWidth + rightPadding) {
 						if (me.Flags == MouseFlags.Button1Clicked) {
 							if (Menus [i].IsTopLevel) {
-								var menu = new Menu (this, i, 0, Menus [i]);
+								ViewToScreen (i, 0, out int rx, out int ry);
+								var menu = new Menu (this, rx, ry, Menus [i]);
 								menu.Run (Menus [i].Action);
 								menu.Dispose ();
 							} else if (!IsMenuOpen) {

+ 82 - 2
UnitTests/Menus/ContextMenuTests.cs

@@ -228,7 +228,7 @@ namespace Terminal.Gui.MenuTests {
 			var oldKey = Key.Null;
 			var cm = new ContextMenu ();
 
-			cm.KeyChanged += (s,e) => oldKey = e.OldKey;
+			cm.KeyChanged += (s, e) => oldKey = e.OldKey;
 
 			cm.Key = Key.Space | Key.CtrlMask;
 			Assert.Equal (Key.Space | Key.CtrlMask, cm.Key);
@@ -241,7 +241,7 @@ namespace Terminal.Gui.MenuTests {
 			var oldMouseFlags = new MouseFlags ();
 			var cm = new ContextMenu ();
 
-			cm.MouseFlagsChanged += (s,e) => oldMouseFlags = e.OldValue;
+			cm.MouseFlagsChanged += (s, e) => oldMouseFlags = e.OldValue;
 
 			cm.MouseFlags = MouseFlags.Button2Clicked;
 			Assert.Equal (MouseFlags.Button2Clicked, cm.MouseFlags);
@@ -902,5 +902,85 @@ namespace Terminal.Gui.MenuTests {
 			Assert.True (top.Subviews [1].ProcessKey (new KeyEvent (Key.F10 | Key.ShiftMask, new KeyModifiers ())));
 			Assert.Null (tf.ContextMenu.MenuBar);
 		}
+
+		[Fact, AutoInitShutdown]
+		public void Draw_A_ContextManu_Over_A_Dialog ()
+		{
+			var top = Application.Top;
+			var win = new Window ("Window");
+			top.Add (win);
+			Application.Begin (top);
+			((FakeDriver)Application.Driver).SetBufferSize (20, 15);
+
+			Assert.Equal (new Rect (0, 0, 20, 15), win.Frame);
+			TestHelpers.AssertDriverContentsWithFrameAre (@"
+┌ Window ──────────┐
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+└──────────────────┘", output);
+
+			var dialog = new Dialog ("Dialog") { X = 2, Y = 2, Width = 15, Height = 4 };
+			dialog.Add (new TextField ("Test") { X = Pos.Center (), Width = 10 });
+			var rs = Application.Begin (dialog);
+
+			Assert.Equal (new Rect (2, 2, 15, 4), dialog.Frame);
+			TestHelpers.AssertDriverContentsWithFrameAre (@"
+┌ Window ──────────┐
+│                  │
+│ ┌ Dialog ─────┐  │
+│ │ Test        │  │
+│ │             │  │
+│ └─────────────┘  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+└──────────────────┘", output);
+
+			ReflectionTools.InvokePrivate (
+				typeof (Application),
+				"ProcessMouseEvent",
+				new MouseEvent () {
+					X = 9,
+					Y = 3,
+					Flags = MouseFlags.Button3Clicked
+				});
+
+			var firstIteration = false;
+			Application.RunMainLoopIteration (ref rs, true, ref firstIteration);
+			TestHelpers.AssertDriverContentsWithFrameAre (@"
+┌ Window ──────────┐
+│                  │
+│ ┌ Dialog ─────┐  │
+│ │ Test        │  │
+┌───────────────────
+│ Select All   Ctrl+
+│ Delete All   Ctrl+
+│ Copy         Ctrl+
+│ Cut          Ctrl+
+│ Paste        Ctrl+
+│ Undo         Ctrl+
+│ Redo         Ctrl+
+└───────────────────
+│                  │
+└──────────────────┘", output);
+
+			Application.End (rs);
+		}
 	}
 }

+ 9 - 9
UnitTests/Menus/MenuTests.cs

@@ -109,7 +109,7 @@ namespace Terminal.Gui.MenuTests {
 					new MenuItem ("_New", "Creates new file.", New)
 				})
 			});
-			menu.MenuOpening += (s,e) => {
+			menu.MenuOpening += (s, e) => {
 				Assert.Equal ("_File", e.CurrentMenu.Title);
 				Assert.Equal ("_New", e.CurrentMenu.Children [0].Title);
 				Assert.Equal ("Creates new file.", e.CurrentMenu.Children [0].Help);
@@ -130,7 +130,7 @@ namespace Terminal.Gui.MenuTests {
 				mi.Action ();
 				Assert.Equal ("Copy", miAction);
 			};
-			menu.MenuClosing += (s,e) => {
+			menu.MenuClosing += (s, e) => {
 				Assert.False (isMenuClosed);
 				if (cancelClosing) {
 					e.Cancel = true;
@@ -196,7 +196,7 @@ Edit
 					new MenuItem ("_Save", "Saves the file.", null, null)
 				})
 			});
-			menu.MenuOpened += (s,e) => {
+			menu.MenuOpened += (s, e) => {
 				miCurrent = e.MenuItem;
 				mCurrent = menu.openMenu;
 			};
@@ -380,12 +380,12 @@ Edit
 				}),
 				new MenuBarItem ("_About", "Top-Level", () => miAction ="About")
 			});
-			menu.MenuOpening += (s,e) => mbiCurrent = e.CurrentMenu;
+			menu.MenuOpening += (s, e) => mbiCurrent = e.CurrentMenu;
 			menu.MenuOpened += (s, e) => {
 				miCurrent = e.MenuItem;
 				mCurrent = menu.openCurrentMenu;
 			};
-			menu.MenuClosing += (s,e) => {
+			menu.MenuClosing += (s, e) => {
 				mbiCurrent = null;
 				miCurrent = null;
 				mCurrent = null;
@@ -1689,7 +1689,7 @@ Edit
 └──────────────────────────────────────┘", output);
 
 			Assert.True (win.ProcessHotKey (new KeyEvent (Key.F9, new KeyModifiers ())));
-			win.Redraw (win.Bounds);
+			top.Redraw (top.Bounds);
 			TestHelpers.AssertDriverContentsWithFrameAre (@"
 ┌──────────────────────────────────────┐
 │ File  Edit                           │
@@ -1701,7 +1701,7 @@ Edit
 └──────────────────────────────────────┘", output);
 
 			Assert.True (menu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ())));
-			win.Redraw (win.Bounds);
+			top.Redraw (top.Bounds);
 			TestHelpers.AssertDriverContentsWithFrameAre (@"
 ┌──────────────────────────────────────┐
 │ File  Edit                           │
@@ -1713,7 +1713,7 @@ Edit
 └──────────────────────────────────────┘", output);
 
 			Assert.True (menu.openMenu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ())));
-			win.Redraw (win.Bounds);
+			top.Redraw (top.Bounds);
 			TestHelpers.AssertDriverContentsWithFrameAre (@"
 ┌──────────────────────────────────────┐
 │ File  Edit                           │
@@ -1725,7 +1725,7 @@ Edit
 └──────────────────────────────────────┘", output);
 
 			Assert.True (menu.openMenu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ())));
-			win.Redraw (win.Bounds);
+			top.Redraw (top.Bounds);
 			TestHelpers.AssertDriverContentsWithFrameAre (@"
 ┌──────────────────────────────────────┐
 │ File  Edit                           │

+ 3 - 3
UnitTests/TopLevels/ToplevelTests.cs

@@ -1487,10 +1487,10 @@ namespace Terminal.Gui.TopLevelTests {
 			btnPopup.Clicked += (s, e) => {
 				var viewToScreen = btnPopup.ViewToScreen (top.Frame);
 				var view = new View () { X = 1, Y = viewToScreen.Y + 1, Width = 18, Height = 5 };
-				Application.IterationComplete += Application_IterationComplete;
+				Application.Current.DrawContentComplete += Current_DrawContentComplete;
 				top.Add (view);
 
-				void Application_IterationComplete ()
+				void Current_DrawContentComplete (object sender, DrawEventArgs e)
 				{
 					Assert.Equal (new Rect (1, 14, 18, 5), view.Frame);
 
@@ -1502,7 +1502,7 @@ namespace Terminal.Gui.TopLevelTests {
 					top.Move (2, 17);
 					View.Driver.AddStr ("Three");
 
-					Application.IterationComplete -= Application_IterationComplete;
+					Application.Current.DrawContentComplete -= Current_DrawContentComplete;
 				}
 			};
 			var dialog = new Dialog ("Dialog", 15, 10, btnPopup);