From 380cef8da268b3544525c4cbc4e6dd5d299466a5 Mon Sep 17 00:00:00 2001 From: Sandy Armstrong Date: Tue, 12 Nov 2019 15:49:17 -0800 Subject: [Debugger] Prevent NREs when allowPinning=false --- .../MonoDevelop.Debugger/ObjectValue/Mac/MacObjectValueTreeView.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'main/src/addins') diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/ObjectValue/Mac/MacObjectValueTreeView.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/ObjectValue/Mac/MacObjectValueTreeView.cs index 2a43053cfe..47bf09fbc0 100644 --- a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/ObjectValue/Mac/MacObjectValueTreeView.cs +++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/ObjectValue/Mac/MacObjectValueTreeView.cs @@ -191,9 +191,11 @@ namespace MonoDevelop.Debugger public PinnedWatch PinnedWatch { get => pinnedWatch; set { - if (pinnedWatch != value) { + if (pinnedWatch != value && pinColumn != null) { pinnedWatch = value; Runtime.RunInMainThread (() => { + if (pinColumn == null) + return; if (value == null) { pinColumn.MinWidth = pinColumn.MaxWidth = pinColumn.Width = MacDebuggerObjectPinView.MinWidth; } else { -- cgit v1.2.3 From 1758e1ac67a3f9e41444f6716ec76d08090dc8b2 Mon Sep 17 00:00:00 2001 From: Sandy Armstrong Date: Tue, 12 Nov 2019 16:02:09 -0800 Subject: [Debugger] Simplify PinnedWatchView, allow scrolling children via popover Currently, the editor intercepts scrolling events that an adornment such as the PinnedWatchView might want to receive. This prevents such an adornment from being properly scrollable. Looking at how pinned watches work on Windows, however, the watch itself cannot be expanded. Rather, the user can click an expand button to see the child items in a popup. Inspired by this, I have removed scrolling and expansion from the PinnedWatchView, and made it so hovering a watch shows the same popover tooltip (which _is_ scrollable, as it's a child window) that one sees when hovering a value in the editor. A few notes: * Changed the data source to not add child nodes at all when `AllowExpanding` is not set on the tree view. This ensures there will be no disclosure triangle. * Pinned watches whose values do not have children will not get a tooltip. * When hovering a pinned watch, the root node will always be expanded. * The only way to dismiss the watch's popover tooltip is to press ESC or click elsewhere. This actually feels pretty good. * Child expansion state in the tooltip is preserved as long as the watch remains pinned. Fixes: https://devdiv.visualstudio.com/DevDiv/_workitems/edit/999603 --- .../PinnedWatches/PinnedWatchView.cs | 60 +++++++++++----------- .../QuickInfo/MacDebuggerTooltipWindow.cs | 5 ++ .../Mac/MacObjectValueTreeViewDataSource.cs | 20 +++++--- 3 files changed, 47 insertions(+), 38 deletions(-) (limited to 'main/src/addins') diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/PinnedWatches/PinnedWatchView.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/PinnedWatches/PinnedWatchView.cs index 6827a7ae10..b5ed4e07f2 100644 --- a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/PinnedWatches/PinnedWatchView.cs +++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/PinnedWatches/PinnedWatchView.cs @@ -32,12 +32,15 @@ using Mono.Debugging.Client; namespace MonoDevelop.Debugger.VSTextView.PinnedWatches { - sealed class PinnedWatchView : NSScrollView + sealed class PinnedWatchView : NSView { + readonly PinnedWatch watch; + readonly StackFrame frame; readonly ObjectValueTreeViewController controller; readonly NSLayoutConstraint heightConstraint; readonly NSLayoutConstraint widthConstraint; readonly MacObjectValueTreeView treeView; + MacDebuggerTooltipWindow popover; NSLayoutConstraint superHeightConstraint; NSLayoutConstraint superWidthConstraint; ObjectValue objectValue; @@ -45,26 +48,27 @@ namespace MonoDevelop.Debugger.VSTextView.PinnedWatches public PinnedWatchView (PinnedWatch watch, StackFrame frame) { - HasVerticalScroller = true; - AutohidesScrollers = true; + this.watch = watch ?? throw new ArgumentNullException (nameof (watch)); + this.frame = frame; controller = new ObjectValueTreeViewController (); controller.SetStackFrame (frame); controller.AllowEditing = true; + controller.AllowExpanding = false; treeView = controller.GetMacControl (headersVisible: false, compactView: true, allowPinning: true); controller.PinnedWatch = watch; if (watch.Value != null) - controller.AddValue (watch.Value); + controller.AddValue (objectValue = watch.Value); var rect = treeView.Frame; if (rect.Height < 1) treeView.Frame = new CoreGraphics.CGRect (rect.X, rect.Y, rect.Width, 19); - DocumentView = treeView; + AddSubview (treeView); Frame = treeView.Frame; heightConstraint = HeightAnchor.ConstraintEqualToConstant (treeView.Frame.Height); @@ -76,6 +80,27 @@ namespace MonoDevelop.Debugger.VSTextView.PinnedWatches DebuggingService.ResumedEvent += OnDebuggerResumed; DebuggingService.PausedEvent += OnDebuggerPaused; treeView.Resized += OnTreeViewResized; + + AddTrackingArea (new NSTrackingArea ( + default, + NSTrackingAreaOptions.ActiveInActiveApp | + NSTrackingAreaOptions.InVisibleRect | + NSTrackingAreaOptions.MouseEnteredAndExited, + this, + null)); + } + + public override void MouseEntered (NSEvent theEvent) + { + if (popover != null && popover.Shown) + return; + + if (objectValue != null && objectValue.HasChildren) { + if (popover == null) + popover = new MacDebuggerTooltipWindow (watch.Location, frame, objectValue, watch); + popover.Show (treeView.Frame, this, NSRectEdge.MaxXEdge); + popover.Expand (); + } } public void SetObjectValue (ObjectValue value) @@ -136,41 +161,16 @@ namespace MonoDevelop.Debugger.VSTextView.PinnedWatches superHeightConstraint.Constant = height; superWidthConstraint.Constant = width; - -#if REPARENT_SO_SCROLLING_WORKS - // Find our parent CocoaEditorGridView - var gridView = textView.Superview; - while (gridView != null && gridView.GetType ().Name != CocoaEditorGridView) - gridView = gridView.Superview; - - if (gridView == null) - return; - - // Find the CocoaTextViewScrollView - NSView textViewScrollView = null; - foreach (var child in gridView.Subviews) { - if (child.GetType ().Name == CocoaTextViewScrollView) { - textViewScrollView = child; - break; - } - } - - materialView.RemoveFromSuperview (); - - gridView.AddSubview (materialView, NSWindowOrderingMode.Above, textViewScrollView); -#endif } void OnDebuggerResumed (object sender, EventArgs e) { controller.ChangeCheckpoint (); - controller.AllowExpanding = false; controller.AllowEditing = false; } void OnDebuggerPaused (object sender, EventArgs e) { - controller.AllowExpanding = true; controller.AllowEditing = true; } diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/QuickInfo/MacDebuggerTooltipWindow.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/QuickInfo/MacDebuggerTooltipWindow.cs index 1f508f5eca..80ffe9bc4a 100644 --- a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/QuickInfo/MacDebuggerTooltipWindow.cs +++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.VSTextView/QuickInfo/MacDebuggerTooltipWindow.cs @@ -78,6 +78,11 @@ namespace MonoDevelop.Debugger treeView.Resized += OnTreeViewResized; } + public void Expand () + { + treeView.ExpandItem (treeView.ItemAtRow (0), false); + } + public DebuggerSession GetDebuggerSession () { return controller.GetStackFrame ()?.DebuggerSession; diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/ObjectValue/Mac/MacObjectValueTreeViewDataSource.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/ObjectValue/Mac/MacObjectValueTreeViewDataSource.cs index a7e57261df..d8d96a6a4a 100644 --- a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/ObjectValue/Mac/MacObjectValueTreeViewDataSource.cs +++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/ObjectValue/Mac/MacObjectValueTreeViewDataSource.cs @@ -75,11 +75,13 @@ namespace MonoDevelop.Debugger parent.Children.Add (value); - foreach (var child in node.Children) - Add (value, child); + if (treeView.AllowExpanding) { + foreach (var child in node.Children) + Add (value, child); - if (node.HasChildren && !node.ChildrenLoaded) - Add (value, new LoadingObjectValueNode (node)); + if (node.HasChildren && !node.ChildrenLoaded) + Add (value, new LoadingObjectValueNode (node)); + } } void Insert (MacObjectValueNode parent, int index, ObjectValueNode node) @@ -89,11 +91,13 @@ namespace MonoDevelop.Debugger parent.Children.Insert (index, value); - foreach (var child in node.Children) - Add (value, child); + if (treeView.AllowExpanding) { + foreach (var child in node.Children) + Add (value, child); - if (node.HasChildren && !node.ChildrenLoaded) - Add (value, new LoadingObjectValueNode (node)); + if (node.HasChildren && !node.ChildrenLoaded) + Add (value, new LoadingObjectValueNode (node)); + } } void Remove (MacObjectValueNode node, List removed) -- cgit v1.2.3