public static nfloat GetOptimalWidth(MacObjectValueTreeView treeView, ObjectValueNode node)
        {
            nfloat optimalWidth = MarginSize;

            var editable    = treeView.AllowWatchExpressions && node.Parent is RootObjectValueNode;
            var placeholder = string.Empty;
            var name        = node.Name;

            if (node.IsUnknown)
            {
            }
            else if (node.IsError || node.IsNotSupported)
            {
            }
            else if (node.IsImplicitNotSupported)
            {
            }
            else if (node.IsEvaluating)
            {
            }
            else if (node.IsEnumerable)
            {
            }
            else if (node is AddNewExpressionObjectValueNode)
            {
                placeholder = GettextCatalog.GetString("Add new expression");
                name        = string.Empty;
                editable    = true;
            }

            optimalWidth += ImageSize;
            optimalWidth += RowCellSpacing;

            var value = editable && string.IsNullOrEmpty(name) ? placeholder : name;

            optimalWidth += GetWidthForString(treeView.CustomFont, value);

            if (MacObjectValueTreeView.ValidObjectForPreviewIcon(node))
            {
                optimalWidth += RowCellSpacing;
                optimalWidth += ImageSize;
            }

            optimalWidth += MarginSize;

            return(optimalWidth);
        }
        void OnPreviewButtonClicked(object sender, EventArgs e)
        {
            if (!TreeView.DebuggerService.CanQueryDebugger || PreviewWindowManager.IsVisible)
            {
                return;
            }

            if (!MacObjectValueTreeView.ValidObjectForPreviewIcon(Node))
            {
                return;
            }

            // convert the buttons frame to window coords
            var buttonLocation = PreviewButton.ConvertPointToView(CoreGraphics.CGPoint.Empty, null);

            // now convert the frame to absolute screen coordinates
            buttonLocation = PreviewButton.Window.ConvertPointToScreen(buttonLocation);

            var nativeRoot = MacInterop.GtkQuartz.GetWindow(IdeApp.Workbench.RootWindow);

            // convert to root window coordinates
            buttonLocation = nativeRoot.ConvertPointFromScreen(buttonLocation);
            // the Cocoa Y axis is flipped, convert to Gtk
            buttonLocation.Y = nativeRoot.Frame.Height - buttonLocation.Y;
            // Gtk coords don't include the toolbar and decorations ofsset, so substract it
            buttonLocation.Y -= nativeRoot.Frame.Height - nativeRoot.ContentView.Frame.Height;

            int width  = (int)PreviewButton.Frame.Width;
            int height = (int)PreviewButton.Frame.Height;

            var buttonArea = new Gdk.Rectangle((int)buttonLocation.X, (int)buttonLocation.Y, width, height);
            var val        = Node.GetDebuggerObjectValue();

            SetPreviewButtonIcon(PreviewButtonIcon.Active);

            DebuggingService.ShowPreviewVisualizer(val, IdeApp.Workbench.RootWindow, buttonArea);

            var metadata = new Dictionary <string, object> ();

            metadata["UIElementName"]    = TreeView.UIElementName;
            metadata["ObjectValue.Type"] = val.TypeName;

            Counters.OpenedPreviewer.Inc(1, null, metadata);
        }
        protected override void UpdateContents()
        {
            if (Node == null)
            {
                return;
            }

            foreach (var constraint in constraints)
            {
                constraint.Active = false;
                constraint.Dispose();
            }
            constraints.Clear();

            OptimalWidth = MarginSize;

            bool selected = Superview is NSTableRowView rowView && rowView.Selected;
            var  iconName = ObjectValueTreeViewController.GetIcon(Node.Flags);

            ImageView.Image = GetImage(iconName, Gtk.IconSize.Menu, selected);
            constraints.Add(ImageView.CenterYAnchor.ConstraintEqualToAnchor(CenterYAnchor));
            constraints.Add(ImageView.LeadingAnchor.ConstraintEqualToAnchor(LeadingAnchor, MarginSize));
            constraints.Add(ImageView.WidthAnchor.ConstraintEqualToConstant(ImageSize));
            constraints.Add(ImageView.HeightAnchor.ConstraintEqualToConstant(ImageSize));

            OptimalWidth += ImageView.Image.Size.Width;
            OptimalWidth += RowCellSpacing;

            var editable    = TreeView.AllowWatchExpressions && Node.Parent is RootObjectValueNode;
            var textColor   = NSColor.ControlText;
            var placeholder = string.Empty;
            var name        = Node.Name;

            if (Node.IsUnknown)
            {
                if (TreeView.DebuggerService.Frame != null)
                {
                    textColor = NSColor.FromCGColor(GetCGColor(Styles.ObjectValueTreeValueDisabledText));
                }
            }
            else if (Node.IsError || Node.IsNotSupported)
            {
            }
            else if (Node.IsImplicitNotSupported)
            {
            }
            else if (Node.IsEvaluating)
            {
                if (Node.GetIsEvaluatingGroup())
                {
                    textColor = NSColor.FromCGColor(GetCGColor(Styles.ObjectValueTreeValueDisabledText));
                }
            }
            else if (Node.IsEnumerable)
            {
            }
            else if (Node is AddNewExpressionObjectValueNode)
            {
                placeholder = GettextCatalog.GetString("Add new expression");
                name        = string.Empty;
                editable    = true;
            }
            else if (TreeView.Controller.GetNodeHasChangedSinceLastCheckpoint(Node))
            {
                textColor = NSColor.FromCGColor(GetCGColor(Styles.ObjectValueTreeValueModifiedText));
            }

            TextField.PlaceholderAttributedString = GetAttributedPlaceholderString(placeholder);
            TextField.AttributedStringValue       = GetAttributedString(name);
            TextField.TextColor = textColor;
            TextField.Editable  = editable;
            UpdateFont(TextField);
            TextField.SizeToFit();

            OptimalWidth += TextField.Frame.Width;

            constraints.Add(TextField.CenterYAnchor.ConstraintEqualToAnchor(CenterYAnchor));
            constraints.Add(TextField.LeadingAnchor.ConstraintEqualToAnchor(ImageView.TrailingAnchor, RowCellSpacing));

            if (MacObjectValueTreeView.ValidObjectForPreviewIcon(Node))
            {
                SetPreviewButtonIcon(PreviewButtonIcon.Hidden);

                if (!previewIconVisible)
                {
                    AddSubview(PreviewButton);
                    previewIconVisible = true;
                }

                constraints.Add(TextField.WidthAnchor.ConstraintGreaterThanOrEqualToConstant(TextField.Frame.Width));
                constraints.Add(PreviewButton.CenterYAnchor.ConstraintEqualToAnchor(CenterYAnchor));
                constraints.Add(PreviewButton.LeadingAnchor.ConstraintEqualToAnchor(TextField.TrailingAnchor, RowCellSpacing));
                constraints.Add(PreviewButton.WidthAnchor.ConstraintEqualToConstant(ImageSize));
                constraints.Add(PreviewButton.HeightAnchor.ConstraintEqualToConstant(ImageSize));

                OptimalWidth += RowCellSpacing;
                OptimalWidth += PreviewButton.Frame.Width;
            }
            else
            {
                if (previewIconVisible)
                {
                    PreviewButton.RemoveFromSuperview();
                    previewIconVisible = false;
                }

                constraints.Add(TextField.TrailingAnchor.ConstraintEqualToAnchor(TrailingAnchor, -MarginSize));
            }

            foreach (var constraint in constraints)
            {
                constraint.Active = true;
            }

            OptimalWidth += MarginSize;
        }
        protected override void UpdateContents()
        {
            if (Node == null)
            {
                return;
            }

            foreach (var constraint in constraints)
            {
                constraint.Active = false;
                constraint.Dispose();
            }
            constraints.Clear();

            OptimalWidth = MarginSize;

            var editable             = TreeView.AllowWatchExpressions && Node.Parent is RootObjectValueNode;
            var selected             = Superview is NSTableRowView rowView && rowView.Selected;
            var iconName             = ObjectValueTreeViewController.GetIcon(Node.Flags);
            var wrapper              = (MacObjectValueNode)ObjectValue;
            var textColor            = NSColor.ControlText;
            var showAddNewExpression = false;
            var placeholder          = string.Empty;
            var name = Node.Name;

            if (Node.IsUnknown)
            {
                if (!selected && TreeView.DebuggerService.Frame != null)
                {
                    textColor = NSColor.FromCGColor(GetCGColor(Styles.ObjectValueTreeValueDisabledText));
                }
            }
            else if (Node.IsError || Node.IsNotSupported)
            {
            }
            else if (Node.IsImplicitNotSupported)
            {
            }
            else if (Node.IsEvaluating)
            {
                if (!selected && Node.GetIsEvaluatingGroup())
                {
                    textColor = NSColor.FromCGColor(GetCGColor(Styles.ObjectValueTreeValueDisabledText));
                }
            }
            else if (Node.IsEnumerable)
            {
            }
            else if (Node is AddNewExpressionObjectValueNode)
            {
                placeholder          = GettextCatalog.GetString("Add item to watch");
                showAddNewExpression = true;
                name     = string.Empty;
                editable = true;
            }
            else if (!selected && TreeView.Controller.GetNodeHasChangedSinceLastCheckpoint(Node))
            {
                textColor = NSColor.FromCGColor(GetCGColor(Styles.ObjectValueTreeValueModifiedText));
            }

            NSView firstView;

            if (showAddNewExpression)
            {
                AddNewExpressionButton.Image = GetImage("gtk-add", Gtk.IconSize.Menu, selected);
                firstView = AddNewExpressionButton;

                if (!addNewExpressionVisible)
                {
                    ImageView.RemoveFromSuperview();
                    AddSubview(AddNewExpressionButton);
                    addNewExpressionVisible = true;
                }
            }
            else
            {
                ImageView.Image = GetImage(iconName, Gtk.IconSize.Menu, selected);
                firstView       = ImageView;

                if (addNewExpressionVisible)
                {
                    AddNewExpressionButton.RemoveFromSuperview();
                    addNewExpressionVisible = false;
                    AddSubview(ImageView);
                }
            }

            constraints.Add(firstView.CenterYAnchor.ConstraintEqualToAnchor(CenterYAnchor));
            constraints.Add(firstView.LeadingAnchor.ConstraintEqualToAnchor(LeadingAnchor, MarginSize));
            constraints.Add(firstView.WidthAnchor.ConstraintEqualToConstant(ImageSize));
            constraints.Add(firstView.HeightAnchor.ConstraintEqualToConstant(ImageSize));

            OptimalWidth += ImageSize;
            OptimalWidth += RowCellSpacing;

            TextField.PlaceholderAttributedString = GetAttributedPlaceholderString(placeholder);
            TextField.StringValue = name;
            TextField.TextColor   = textColor;
            TextField.Editable    = editable;
            UpdateFont(TextField);
            TextField.SizeToFit();
            ImageView.AccessibilityTitle = ObjectValueTreeViewController.GetAccessibilityTitleForIcon(
                Node.Flags,
                GettextCatalog.GetString("Object Name"));

            var value     = editable && string.IsNullOrEmpty(name) ? placeholder : name;
            var textWidth = GetWidthForString(TextField.Font, value);

            OptimalWidth += textWidth;

            NSView textView;

            if (editing)
            {
                textView = editorTextView;

                var span = editor.TextBuffer.CurrentSnapshot.GetEntireSpan();
                editor.TextBuffer.Replace(span, name);

                if (!editorTextViewVisible)
                {
                    TextField.RemoveFromSuperview();
                    editorTextViewVisible = true;
                    AddSubview(textView);
                }

                constraints.Add(textView.TopAnchor.ConstraintEqualToAnchor(TopAnchor, (nfloat)editor.FormattedLineSource.BaseIndentation));
                constraints.Add(textView.BottomAnchor.ConstraintEqualToAnchor(BottomAnchor, (nfloat)editor.FormattedLineSource.BaseIndentation));
            }
            else
            {
                textView = TextField;

                if (editorTextViewVisible)
                {
                    editorTextView.RemoveFromSuperview();
                    editorTextViewVisible = false;
                    AddSubview(TextField);
                }

                constraints.Add(TextField.CenterYAnchor.ConstraintEqualToAnchor(CenterYAnchor));
            }

            constraints.Add(textView.LeadingAnchor.ConstraintEqualToAnchor(firstView.TrailingAnchor, RowCellSpacing));

            if (!editing && MacObjectValueTreeView.ValidObjectForPreviewIcon(Node))
            {
                SetPreviewButtonIcon(PreviewButtonIcon.Hidden);

                if (!previewIconVisible)
                {
                    AddSubview(PreviewButton);
                    previewIconVisible = true;
                }

                constraints.Add(TextField.WidthAnchor.ConstraintGreaterThanOrEqualToConstant(textWidth));
                constraints.Add(PreviewButton.CenterYAnchor.ConstraintEqualToAnchor(CenterYAnchor));
                constraints.Add(PreviewButton.LeadingAnchor.ConstraintEqualToAnchor(TextField.TrailingAnchor, RowCellSpacing));
                constraints.Add(PreviewButton.WidthAnchor.ConstraintEqualToConstant(ImageSize));
                constraints.Add(PreviewButton.HeightAnchor.ConstraintEqualToConstant(ImageSize));

                OptimalWidth += RowCellSpacing;
                OptimalWidth += ImageSize;
            }
            else
            {
                if (previewIconVisible)
                {
                    PreviewButton.RemoveFromSuperview();
                    previewIconVisible = false;
                }

                constraints.Add(textView.TrailingAnchor.ConstraintEqualToAnchor(TrailingAnchor, -MarginSize));
            }

            foreach (var constraint in constraints)
            {
                constraint.Active = true;
            }

            OptimalWidth += MarginSize;

            wrapper.OptimalNameFont  = TreeView.CustomFont;
            wrapper.OptimalNameWidth = OptimalWidth;
            wrapper.OptimalXOffset   = Frame.X;
        }