|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using AppKit;
using Foundation;
using ObjCRuntime;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.VisualStudio.Text.Differencing;
namespace Microsoft.CodeAnalysis.Editor.Implementation.Preview
{
internal class PreviewPane : NSView
{
private DifferenceViewerPreview? _differenceViewerPreview;
private readonly NSTextField? titleField;
public PreviewPane(string? id, string? title, Uri? helpLink, string? helpLinkToolTipText, IReadOnlyList<object> previewContent)
{
_differenceViewerPreview = (DifferenceViewerPreview)previewContent[0];
var view = ((ICocoaDifferenceViewer)_differenceViewerPreview.Viewer).VisualElement;
var originalSize = view.Frame.Size;
this.TranslatesAutoresizingMaskIntoConstraints = false;
// === Title ===
// Title is in a stack view to help with padding
var titlePlaceholder = new NSStackView()
{
Orientation = NSUserInterfaceLayoutOrientation.Vertical,
EdgeInsets = new NSEdgeInsets(5, 0, 5, 0),
Alignment = NSLayoutAttribute.Leading,
TranslatesAutoresizingMaskIntoConstraints = false
};
// TODO: missing icon
this.titleField = new NSTextField()
{
Editable = false,
Bordered = false,
BackgroundColor = NSColor.ControlBackground,
DrawsBackground = false,
};
titlePlaceholder.AddArrangedSubview(titleField);
AddSubview(titlePlaceholder);
// === Preview View ===
// This is the actual view, that shows the diff
view.TranslatesAutoresizingMaskIntoConstraints = false;
NSLayoutConstraint.Create(view, NSLayoutAttribute.Width, NSLayoutRelation.GreaterThanOrEqual, 1, originalSize.Width).Active = true;
NSLayoutConstraint.Create(view, NSLayoutAttribute.Height, NSLayoutRelation.GreaterThanOrEqual, 1, originalSize.Height).Active = true;
view.Subviews[0].TranslatesAutoresizingMaskIntoConstraints = false;
view.WantsLayer = true;
AddSubview(view);
// === Constraints ===
var constraints = new NSLayoutConstraint[]
{
// Title
NSLayoutConstraint.Create(titlePlaceholder, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this, NSLayoutAttribute.Top, 1, 0),
NSLayoutConstraint.Create(titlePlaceholder, NSLayoutAttribute.Leading, NSLayoutRelation.Equal, this, NSLayoutAttribute.Leading, 1, 0),
NSLayoutConstraint.Create(titlePlaceholder, NSLayoutAttribute.Trailing, NSLayoutRelation.Equal, this, NSLayoutAttribute.Trailing, 1, 0),
// Preview View
NSLayoutConstraint.Create(view, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, this, NSLayoutAttribute.Bottom, 1, 0),
NSLayoutConstraint.Create(view, NSLayoutAttribute.Leading, NSLayoutRelation.Equal, this, NSLayoutAttribute.Leading, 1, 0),
NSLayoutConstraint.Create(view, NSLayoutAttribute.Trailing, NSLayoutRelation.Equal, this, NSLayoutAttribute.Trailing, 1, 0),
// subviews
NSLayoutConstraint.Create(view.Subviews[0], NSLayoutAttribute.Top, NSLayoutRelation.Equal, view, NSLayoutAttribute.Top, 1, 0),
NSLayoutConstraint.Create(view.Subviews[0], NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, view, NSLayoutAttribute.Bottom, 1, 0),
NSLayoutConstraint.Create(view.Subviews[0], NSLayoutAttribute.Left, NSLayoutRelation.Equal, view, NSLayoutAttribute.Left, 1, 0),
NSLayoutConstraint.Create(view.Subviews[0], NSLayoutAttribute.Right, NSLayoutRelation.Equal, view, NSLayoutAttribute.Right, 1, 0),
};
if (GenerateAttributeString(id, title, helpLink, helpLinkToolTipText) is NSAttributedString attributedStringTitle)
{
this.titleField.AttributedStringValue = attributedStringTitle;
// We do this separately, because the title sometimes isn't there (i.e. no diagnostics ID)
// and we want the preview to stretch to the top
NSLayoutConstraint.Create(view, NSLayoutAttribute.Top, NSLayoutRelation.Equal, titlePlaceholder, NSLayoutAttribute.Bottom, 1, 0).Active = true;
}
else
{
NSLayoutConstraint.Create(view, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this, NSLayoutAttribute.Top, 1, 0).Active = true;
}
NSLayoutConstraint.ActivateConstraints(constraints);
_differenceViewerPreview.Viewer.InlineView.TryMoveCaretToAndEnsureVisible(
new Microsoft.VisualStudio.Text.SnapshotPoint(_differenceViewerPreview.Viewer.InlineView.TextSnapshot, 0));
}
public PreviewPane(NativeHandle ptr)
: base(ptr)
{
}
private static NSAttributedString? GenerateAttributeString(string? id, string? title, Uri? link, string? linkTooltip)
{
if (string.IsNullOrEmpty(title))
return null;
var attributedBuffer = new NSMutableAttributedString();
attributedBuffer.BeginEditing();
var normalText = new NSStringAttributes
{
ForegroundColor = NSColor.ControlText
};
if (!string.IsNullOrEmpty(id))
{
var linkAttributes = new NSStringAttributes
{
LinkUrl = link,
ToolTip = linkTooltip
};
attributedBuffer.Append(new NSAttributedString(id, linkAttributes));
attributedBuffer.Append(new NSAttributedString(": ", normalText));
}
attributedBuffer.Append(new NSAttributedString(title, normalText));
attributedBuffer.EndEditing();
return attributedBuffer;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_differenceViewerPreview?.Dispose();
_differenceViewerPreview = null;
}
base.Dispose(disposing);
}
}
}
|