فهرست منبع

Merge pull request #2479 from BDisp/v2_draw-over-a-modal-view_2478

Fixes #2478. Currently it isn't possible to draw over a modal view.
Tig 2 سال پیش
والد
کامیت
fef4cff53b

+ 5 - 46
Terminal.Gui/Core/Application.cs

@@ -658,7 +658,7 @@ namespace Terminal.Gui {
 					var rx = x - startFrame.X;
 					var ry = y - startFrame.Y;
 					if (top.Visible && top.Frame.Contains (rx, ry)) {
-						var deep = FindDeepestView (top, rx, ry, out resx, out resy);
+						var deep = View.FindDeepestView (top, rx, ry, out resx, out resy);
 						if (deep == null)
 							return FindDeepestMdiView (top, rx, ry, out resx, out resy);
 						if (deep != MdiTop)
@@ -671,45 +671,6 @@ namespace Terminal.Gui {
 			return start;
 		}
 
-		/// <summary>
-		/// Finds the deepest view at the specified coordinates, specified relative to <paramref name="start"/>'s superview.
-		/// </summary>
-		/// <param name="start"></param>
-		/// <param name="x"></param>
-		/// <param name="y"></param>
-		/// <param name="resx"></param>
-		/// <param name="resy"></param>
-		/// <returns></returns>
-		static View FindDeepestView (View start, int x, int y, out int resx, out int resy)
-		{
-			var startFrame = start.Frame;
-
-			if (!startFrame.Contains (x, y)) {
-				resx = 0;
-				resy = 0;
-				return null;
-			}
-			if (start.InternalSubviews != null) {
-				int count = start.InternalSubviews.Count;
-				if (count > 0) {
-					var rx = x - (startFrame.X + start.GetBoundsOffset ().X);
-					var ry = y - (startFrame.Y + start.GetBoundsOffset ().Y);
-					for (int i = count - 1; i >= 0; i--) {
-						View v = start.InternalSubviews [i];
-						if (v.Visible && v.Frame.Contains (rx, ry)) {
-							var deep = FindDeepestView (v, rx, ry, out resx, out resy);
-							if (deep == null)
-								return v;
-							return deep;
-						}
-					}
-				}
-			}
-			resx = x - startFrame.X;
-			resy = y - startFrame.Y;
-			return start;
-		}
-
 		static View FindTopFromView (View view)
 		{
 			View top = view?.SuperView != null && view?.SuperView != Top
@@ -832,7 +793,7 @@ namespace Terminal.Gui {
 				return;
 			}
 
-			var view = FindDeepestView (Current, me.X, me.Y, out int rx, out int ry);
+			var view = View.FindDeepestView (Current, me.X, me.Y, out int rx, out int ry);
 
 			if (view != null && view.WantContinuousButtonPressed) {
 				WantContinuousButtonPressedView = view;
@@ -849,9 +810,7 @@ namespace Terminal.Gui {
 			}
 
 			if (mouseGrabView != null) {
-				view ??= mouseGrabView;
-
-				var newxy = mouseGrabView.ScreenToBounds (me.X, me.Y);
+				var newxy = mouseGrabView.ScreenToView (me.X, me.Y);
 				var nme = new MouseEvent () {
 					X = newxy.X,
 					Y = newxy.Y,
@@ -873,7 +832,7 @@ namespace Terminal.Gui {
 				&& me.Flags != MouseFlags.ReportMousePosition && me.Flags != 0) {
 
 				var top = FindDeepestTop (Top, me.X, me.Y, out _, out _);
-				view = FindDeepestView (top, me.X, me.Y, out rx, out ry);
+				view = View.FindDeepestView (top, me.X, me.Y, out rx, out ry);
 
 				if (view != null && view != MdiTop && top != Current) {
 					MoveCurrent ((Toplevel)top);
@@ -1272,6 +1231,7 @@ namespace Terminal.Gui {
 
 			if (state.Toplevel != Top
 				&& (!Top._needsDisplay.IsEmpty || Top._childNeedsDisplay || Top.LayoutNeeded)) {
+				state.Toplevel.SetNeedsDisplay (state.Toplevel.Bounds);
 				Top.Redraw (Top.Bounds);
 				foreach (var top in toplevels.Reverse ()) {
 					if (top != Top && top != state.Toplevel) {
@@ -1279,7 +1239,6 @@ namespace Terminal.Gui {
 						top.Redraw (top.Bounds);
 					}
 				}
-				state.Toplevel.SetNeedsDisplay (state.Toplevel.Bounds);
 			}
 			if (toplevels.Count == 1 && state.Toplevel == Top
 				&& (Driver.Cols != state.Toplevel.Frame.Width || Driver.Rows != state.Toplevel.Frame.Height)

+ 50 - 5
Terminal.Gui/Core/View.cs

@@ -1038,7 +1038,7 @@ namespace Terminal.Gui {
 				// BUGBUG: v2 - ? - If layoutstyle is absolute, this overwrites the current frame h/w with 0. Hmmm...
 				frame = new Rect (new Point (actX, actY), new Size (w, h)); // Set frame, not Frame!
 
-	
+
 			}
 			//// BUGBUG: I think these calls are redundant or should be moved into just the AutoSize case
 			if (IsInitialized || LayoutStyle == LayoutStyle.Absolute) {
@@ -1047,7 +1047,7 @@ namespace Terminal.Gui {
 				SetMinWidthHeight ();
 				SetNeedsLayout ();
 				SetNeedsDisplay ();
-			}               
+			}
 		}
 
 		void TextFormatter_HotKeyChanged (object sender, KeyChangedEventArgs e)
@@ -1139,8 +1139,11 @@ namespace Terminal.Gui {
 		/// </summary>
 		public void SetSubViewNeedsDisplay ()
 		{
+			if (_childNeedsDisplay) {
+				return;
+			}
 			_childNeedsDisplay = true;
-			if (_superView != null)
+			if (_superView != null && !_superView._childNeedsDisplay)
 				_superView.SetSubViewNeedsDisplay ();
 		}
 
@@ -1490,7 +1493,7 @@ namespace Terminal.Gui {
 		/// <param name="region">View-relative region for the frame to be drawn.</param>
 		/// <param name="padding">The padding to add around the outside of the drawn frame.</param>
 		/// <param name="fill">If set to <see langword="true"/> it fill will the contents.</param>
-		[ObsoleteAttribute ("This method is obsolete in v2. Use use LineCanvas or Frame instead instead.", false)]
+		[ObsoleteAttribute ("This method is obsolete in v2. Use use LineCanvas or Frame instead.", false)]
 		public void DrawFrame (Rect region, int padding = 0, bool fill = false)
 		{
 			var scrRect = ViewToScreen (region);
@@ -1723,7 +1726,7 @@ namespace Terminal.Gui {
 		}
 
 		/// <summary>
-		/// Removes the <see cref="SetNeedsDisplay()"/> and the <see cref="_childNeedsDisplay"/> setting on this view.
+		/// Removes the <see cref="_needsDisplay"/> and the <see cref="_childNeedsDisplay"/> setting on this view.
 		/// </summary>
 		protected void ClearNeedsDisplay ()
 		{
@@ -3480,5 +3483,47 @@ namespace Terminal.Gui {
 
 			return top;
 		}
+
+		/// <summary>
+		/// Finds which view that belong to the <paramref name="start"/> superview at the provided location.
+		/// </summary>
+		/// <param name="start">The superview where to look for.</param>
+		/// <param name="x">The column location in the superview.</param>
+		/// <param name="y">The row location in the superview.</param>
+		/// <param name="resx">The found view screen relative column location.</param>
+		/// <param name="resy">The found view screen relative row location.</param>
+		/// <returns>
+		///  The view that was found at the <praramref name="x"/> and <praramref name="y"/> coordinates.
+		///  <see langword="null"/> if no view was found.
+		/// </returns>
+		public static View FindDeepestView (View start, int x, int y, out int resx, out int resy)
+		{
+			var startFrame = start.Frame;
+
+			if (!startFrame.Contains (x, y)) {
+				resx = 0;
+				resy = 0;
+				return null;
+			}
+			if (start.InternalSubviews != null) {
+				int count = start.InternalSubviews.Count;
+				if (count > 0) {
+					var rx = x - (startFrame.X + start.GetBoundsOffset ().X);
+					var ry = y - (startFrame.Y + start.GetBoundsOffset ().Y);
+					for (int i = count - 1; i >= 0; i--) {
+						View v = start.InternalSubviews [i];
+						if (v.Visible && v.Frame.Contains (rx, ry)) {
+							var deep = FindDeepestView (v, rx, ry, out resx, out resy);
+							if (deep == null)
+								return v;
+							return deep;
+						}
+					}
+				}
+			}
+			resx = x - startFrame.X;
+			resy = y - startFrame.Y;
+			return start;
+		}
 	}
 }

+ 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));
 			}
 		}
 

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

@@ -477,6 +477,11 @@ namespace Terminal.Gui {
 				WantMousePositionReports = host.WantMousePositionReports;
 			}
 
+			if (Application.Current != null) {
+				Application.Current.DrawContentComplete += Current_DrawContentComplete;
+			}
+			Application.RootMouseEvent += Application_RootMouseEvent;
+
 			// Things this view knows how to do
 			AddCommand (Command.LineUp, () => MoveUp ());
 			AddCommand (Command.LineDown, () => MoveDown ());
@@ -502,6 +507,22 @@ namespace Terminal.Gui {
 			AddKeyBinding (Key.Enter, Command.Accept);
 		}
 
+		private void Application_RootMouseEvent (MouseEvent me)
+		{
+			var view = View.FindDeepestView (this, me.X, me.Y, out int rx, out int ry);
+			if (view == this) {
+				var nme = new MouseEvent () {
+					X = rx,
+					Y = ry,
+					Flags = me.Flags,
+					View = view
+				};
+				if (MouseEvent (nme) || me.Flags == MouseFlags.Button1Pressed || me.Flags == MouseFlags.Button1Released) {
+					me.Handled = true;
+				}
+			}
+		}
+
 		internal Attribute DetermineColorSchemeFor (MenuItem item, int index)
 		{
 			if (item != null) {
@@ -511,9 +532,19 @@ 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;
+			}
+			var savedClip = Driver.Clip;
+			Application.Driver.Clip = Application.Top.Frame;
+
 			Driver.SetAttribute (GetNormalColor ());
 			DrawFrame (Bounds, padding: 0, fill: true);
 
@@ -612,6 +643,8 @@ namespace Terminal.Gui {
 					}
 				}
 			}
+			Driver.Clip = savedClip;
+
 			PositionCursor ();
 		}
 
@@ -905,6 +938,15 @@ namespace Terminal.Gui {
 
 			return base.OnEnter (view);
 		}
+
+		protected override void Dispose (bool disposing)
+		{
+			if (Application.Current != null) {
+				Application.Current.DrawContentComplete -= Current_DrawContentComplete;
+			}
+			Application.RootMouseEvent -= Application_RootMouseEvent;
+			base.Dispose (disposing);
+		}
 	}
 
 	/// <summary>
@@ -1322,31 +1364,31 @@ 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 superView = SuperView == null ? Application.Top : SuperView;
+				Point locationOffset;
+				if (superView.Border != null && superView.Border.BorderStyle != BorderStyle.None) {
+					locationOffset = new Point (superView.Frame.X + 1, superView.Frame.Y + 1);
+				} else {
+					locationOffset = 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 +1410,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.Top.Add (openCurrentMenu);
 				}
 				selectedSub = openSubMenu.Count - 1;
 				if (selectedSub > -1 && SelectEnabledItem (openCurrentMenu.barItems.Children, openCurrentMenu.current, out openCurrentMenu.current)) {
@@ -1501,11 +1540,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 +1599,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 +1615,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 +1784,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 +1906,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 ();
+			top.Add (win);
+			Application.Begin (top);
+			((FakeDriver)Application.Driver).SetBufferSize (20, 15);
+
+			Assert.Equal (new Rect (0, 0, 20, 15), win.Frame);
+			TestHelpers.AssertDriverContentsWithFrameAre (@"
+┌──────────────────┐
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+└──────────────────┘", output);
+
+			var dialog = new 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 (@"
+┌──────────────────┐
+│                  │
+│ ┌─────────────┐  │
+│ │ 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 (@"
+┌──────────────────┐
+│                  │
+│ ┌─────────────┐  │
+│ │ 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                           │

+ 125 - 0
UnitTests/TopLevels/ToplevelTests.cs

@@ -1379,5 +1379,130 @@ namespace Terminal.Gui.TopLevelTests {
 
 			Application.End (rs);
 		}
+
+		[Fact, AutoInitShutdown]
+		public void Draw_A_Top_Subview_On_A_Dialog ()
+		{
+			var top = Application.Top;
+			var win = new Window ();
+			top.Add (win);
+			Application.Begin (top);
+			((FakeDriver)Application.Driver).SetBufferSize (20, 20);
+
+			Assert.Equal (new Rect (0, 0, 20, 20), win.Frame);
+			TestHelpers.AssertDriverContentsWithFrameAre (@"
+┌──────────────────┐
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+│                  │
+└──────────────────┘", output);
+
+			var btnPopup = new Button ("Popup");
+			btnPopup.Clicked += (s, e) => {
+				var viewToScreen = btnPopup.ViewToScreen (top.Frame);
+				var view = new View () {
+					X = 1,
+					Y = viewToScreen.Y + 1,
+					Width = 18,
+					Height = 5,
+					Border = new Border () { BorderStyle = BorderStyle.Single }
+				};
+				Application.Current.DrawContentComplete += Current_DrawContentComplete;
+				top.Add (view);
+
+				void Current_DrawContentComplete (object sender, DrawEventArgs e)
+				{
+					Assert.Equal (new Rect (1, 14, 18, 5), view.Frame);
+
+					var savedClip = Application.Driver.Clip;
+					Application.Driver.Clip = top.Frame;
+					view.Redraw (view.Bounds);
+					top.Move (2, 15);
+					View.Driver.AddStr ("One");
+					top.Move (2, 16);
+					View.Driver.AddStr ("Two");
+					top.Move (2, 17);
+					View.Driver.AddStr ("Three");
+					Application.Driver.Clip = savedClip;
+
+					Application.Current.DrawContentComplete -= Current_DrawContentComplete;
+				}
+			};
+			var dialog = new Dialog ("", 15, 10, btnPopup);
+			var rs = Application.Begin (dialog);
+
+			Assert.Equal (new Rect (2, 5, 15, 10), dialog.Frame);
+			TestHelpers.AssertDriverContentsWithFrameAre (@"
+┌──────────────────┐
+│                  │
+│                  │
+│                  │
+│                  │
+│ ┌─────────────┐  │
+│ │             │  │
+│ │             │  │
+│ │             │  │
+│ │             │  │
+│ │             │  │
+│ │             │  │
+│ │             │  │
+│ │  [ Popup ]  │  │
+│ └─────────────┘  │
+│                  │
+│                  │
+│                  │
+│                  │
+└──────────────────┘", output);
+
+			ReflectionTools.InvokePrivate (
+				typeof (Application),
+				"ProcessMouseEvent",
+				new MouseEvent () {
+					X = 9,
+					Y = 13,
+					Flags = MouseFlags.Button1Clicked
+				});
+
+			var firstIteration = false;
+			Application.RunMainLoopIteration (ref rs, true, ref firstIteration);
+			TestHelpers.AssertDriverContentsWithFrameAre (@"
+┌──────────────────┐
+│                  │
+│                  │
+│                  │
+│                  │
+│ ┌─────────────┐  │
+│ │             │  │
+│ │             │  │
+│ │             │  │
+│ │             │  │
+│ │             │  │
+│ │             │  │
+│ │             │  │
+│ │  [ Popup ]  │  │
+│┌────────────────┐│
+││One             ││
+││Two             ││
+││Three           ││
+│└────────────────┘│
+└──────────────────┘", output);
+
+			Application.End (rs);
+		}
 	}
 }