-
Notifications
You must be signed in to change notification settings - Fork 32
Modern ToolTip API
- Feature Team: Editor
- Owner: Christian Gunderman
- Document Type: Dev Design Doc
- Release: 15.6
NOTE: This information is subject to change without notice.
This document captures the design of a cross platform API for rendering ToolTips and ToolTip contents in the editor for use in Visual Studio proper and Visual Studio for Mac.
- Single set of cross platform APIs for surfacing ToolTips to the user at a particular location in the document.
- Single set of abstractions for common ToolTip content primitives (colorized text, stack panel, wrap panel, icons).
- Support programmatic refresh, repositioning, and resizing of opened tooltip by ToolTip invoker.
- Provide a common ToolTip infrastructure for use in Modern Quick Info and Modern Completion.
- Provide an extensibility surface for defining custom content abstractions, allowing extenders and developers to ship their own reusable content abstractions to enable clean layering of code.
- ToolTip and content abstractions should have theme, fonts, and accessible metadata set by the IDE, removing the need for extenders to handle these details.
- Promote a common UX across all IDE ToolTips.
Listed APIs are in primarily located in Microsoft.VisualStudio.Text.UI.dll.
- IToolTipService: Cross platform service for creating an IToolTipPresenter for the particular platform. Language services and IDE features can use this service to create a fully accessible, themed ToolTip with their chosen content on both Visual Studio proper and Visual Studio for Mac.
/// <summary>
/// Cross platform service for the creation and management of ToolTips.
/// </summary>
/// <remarks>
/// This class is a MEF component part and it can be imported via the code in the example.
/// </remarks>
/// <example>
/// [Import]
/// internal IToolTipService tooltipService;
/// </example>
public interface IToolTipService
{
/// <summary>
/// Creates a new non-visible ToolTip presenter.
/// </summary>
/// <param name="textView">
/// The view that owns the tooltip.
/// </param>
/// <param name="parameters">
/// Parameters to create the tooltip with. Default is mouse tracking.
/// </param>
/// <returns>A new non-visible <see cref="IToolTipPresenter"/>.</returns>
IToolTipPresenter CreatePresenter(ITextView textView, ToolTipParameters parameters = null);
}
- IToolTipPresenter: Defines an interface for interacting with IDE tooltips. On calls to StartOrUpdate, the content of the tooltip is updated by converting content to its equivalent platform-specific UI element via the IViewElementFactoryService.
/// <summary>
/// A platform-specific ToolTip implementation.
/// </summary>
/// <remarks>
/// This type is proffered to the IDE via an <see cref="IToolTipPresenterFactory"/> and is
/// always constructed and called purely on the UI thread. Each <see cref="IToolTipPresenter"/>
/// is a single-use object that is responsible for converting the given content to
/// into platform-specific UI elements and displaying them in a popup UI.
/// </remarks>
public interface IToolTipPresenter
{
/// <summary>
/// Invoked upon dismissal of the ToolTip's popup view.
/// </summary>
/// <remarks>
/// This event should be fired regardless of the reason for the popup's dismissal.
/// </remarks>
event EventHandler Dismissed;
/// <summary>
/// Constructs a popup containing a platform-specific UI representation of <paramref name="content"/>.
/// </summary>
/// <remarks>
/// This method can be called multiple times to refresh the content and applicableToSpan.
/// </remarks>
/// <param name="applicableToSpan">The span of text for which the tooltip is kept open.</param>
/// <param name="content">
/// A platform independent representation of the tooltip content. <see cref="IToolTipPresenter"/>s
/// should use the <see cref="IViewElementFactoryService"/> to convert <paramref name="content"/>
/// to platform specific UI elements.
/// </param>
void StartOrUpdate(ITrackingSpan applicableToSpan, IEnumerable<object> content);
/// <summary>
/// Dismisses the popup and causes <see cref="Dismissed"/> to be fired.
/// </summary>
void Dismiss();
}
- IToolTipPresenterFactory: MEF component part exporting an object that creates a platform-specific tooltip presenter for use by the IDE. Visual Studio proper and Visual Studio for Mac both provide a single default implementation. Extenders can override this implementation by exporting a new implementation, ordered before "default".
/// <summary>
/// Proffers a platform-specific <see cref="IToolTipPresenter"/> to the IDE.
/// </summary>
/// <remarks>
/// This class will always be constructed and called purely from the UI thread.
/// Extenders can construct their own presenter and supersede the default
/// one via MEF ordering. Presenter providers should return a new ToolTip each
/// time they are called and should support multiple simultaneous open tips.
/// </remarks>
/// <example>
/// [Export(typeof(IToolTipPresenterFactory))]
/// [Name(nameof("super cool tooltip factory"))]
/// [Order(Before = "default")]
/// </example>
public interface IToolTipPresenterFactory
{
/// <summary>
/// Constructs a new instance of <see cref="IToolTipPresenter"/> for the current platform.
/// </summary>
/// <param name="textView">
/// The view that owns the tooltip.
/// </param>
/// <param name="parameters">
/// Parameters to create the tooltip with. Never null.
/// </param>
/// <returns>A <see cref="IToolTipPresenter"/> for the current platform.</returns>
IToolTipPresenter Create(ITextView textView, ToolTipParameters parameters);
}
- IViewElementFactoryService: Cross platform service for converting from data objects to their platform specific UI representation. This method is used within the IToolTipPresenter implementation to resolve the given objects to platform specific UI (UIElement on Windows).
/// <summary>
/// A service for converting from data objects to their platform specific UI representation.
/// </summary>
/// <remarks>
/// <para>
/// This is a MEF service that can be obtained via the <see cref="ImportAttribute"/> in a MEF exported class.
/// </para>
/// <para>
/// The editor supports <see cref="ClassifiedTextElement"/>s, <see cref="ImageElement"/>s, and <see cref="object"/>
/// on all platforms. Text and image elements are converted to colorized text and images respectively and
/// other objects are displayed as the <see cref="string"/> returned by <see cref="object.ToString()"/>
/// unless an extender exports a <see cref="IViewElementFactory"/> for that type.
/// </para>
/// On Windows only, <see cref="ITextBuffer"/>, <see cref="ITextView"/>, and UIElement are also directly
/// supported.
/// </remarks>
/// <example>
/// [Import]
/// internal IViewElementFactoryService viewElementFactoryService;
/// </example>
public interface IViewElementFactoryService
{
/// <summary>
/// Converts <paramref name="model"/> into an equivalent object of type <typeparamref name="TView"/>.
/// </summary>
/// <typeparam name="TView">The base type of the view element on the specific platform.</typeparam>
/// <param name="textView">The textView that owns the control that will host this view element.</param>
/// <param name="model">The object to convert to a view element.</param>
/// <returns>A new object of type <typeparamref name="TView"/> or null if the conversion is unknown.</returns>
TView CreateViewElement<TView>(ITextView textView, object model) where TView : class;
}
- IViewElementFactory: Defines a reusable conversion from an intermediate object to its platform specific UI element. The IDE has built in conversions defined for several common types of content. See 'Supported Content' section.
/// <summary>
/// Converts from an object to its equivalent platform specific UI element.
/// </summary>
/// <remarks>
/// <para>
/// This type allows the same intermediate type to be rendered on different platforms through
/// the use of platform specific exports that live in that platform's UI layer.
/// </para>
/// <para>
/// You can supersede an existing <see cref="IViewElementFactory"/> for a (to, from) type
/// pair via MEF <see cref="OrderAttribute"/>s.
/// </para>
/// </remarks>
/// <example>
/// [Export(typeof(IViewElementFactory))]
/// [Name("object item")]
/// [Conversion(from: typeof(object), to: typeof(UIElement))]
/// [Order(After = "Foo", Before = "Bar")]
/// </example>
public interface IViewElementFactory
{
/// <summary>
/// Converts <paramref name="model"/> into an equivalent object of type <typeparamref name="TView"/>.
/// </summary>
/// <exception cref="ArgumentException">Thrown if the conversion is unknown or unsupported.</exception>
/// <typeparam name="TView">The base type of the view element on the specific platform.</typeparam>
/// <param name="textView">The view that owns the control that will host this view element.</param>
/// <param name="model">The object to convert to a view element.</param>
/// <returns>A new object of type <typeparamref name="TView"/>.</returns>
TView CreateViewElement<TView>(ITextView textView, object model) where TView : class;
}
- ContainerElement: Wraps a sequence of objects that will be recursively resolved to platform specific UI and hosted in either a stacked formation or a sequential, wrapped formation. On Windows, this resolves to either a wrap panel or a stack panel.
/// <summary>
/// Represents a container of zero or more elements for display in an <see cref="IToolTipPresenter"/>.
/// </summary>
/// <remarks>
/// Elements are translated to platform-specific UI constructs via the <see cref="IViewElementFactoryService"/>.
/// </remarks>
public sealed class ContainerElement
{
/// <summary>
/// Constructs a new container.
/// </summary>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="elements"/> is <c>null</c>.</exception>
/// <param name="style">The layout style for the container.</param>
/// <param name="elements">The <see cref="IViewElementFactoryService"/> elements to display.</param>
public ContainerElement(ContainerElementStyle style, IEnumerable<object> elements)
{
}
}
- ImageElement: Resolves a cross platform ImageId to a platform specific icon UIElement. ImageId is a cross platform proxy-type for the Visual Studio ImageMoniker, which cannot be used on Visual Studio for Mac because COM-style type unification is not supported on the Mono runtime. Conversions
/// <summary>
/// Represents an image in an <see cref="IToolTipService"/> <see cref="IToolTipPresenter"/>.
/// </summary>
///
/// <remarks>
/// <see cref="ImageElement"/>s should be constructed with <see cref="Microsoft.VisualStudio.Core.Imaging.ImageId"/>s
/// that correspond to an image on that platform.
/// </remarks>
public sealed class ImageElement
{
/// <summary>
/// Creates a new instance of an image element.
/// </summary>
/// <param name="iamgeId"> A unique identifier for an image.</param>
public ImageElement(ImageId imageId)
{
}
}
- ClassifiedTextRun: Represents a run of classified text. At resolution time, this text is converted to a platform specific colorized text element with the formatting from the specified classification type applied to it. Must be hosted within a ClassifiedTextElement.
/// <summary>
/// Represents a contiguous run of classified text in an <see cref="IToolTipService"/> <see cref="IToolTipPresenter"/>.
/// </summary>
/// <remarks>
/// Classified text runs live in <see cref="ClassifiedTextElement"/>s and are a string, classification pair. On
/// <see cref="IToolTipPresenter.StartOrUpdate(ITrackingSpan, System.Collections.Generic.IEnumerable{object})"/>,
/// the classified text is converted to a platform-specific run of formatted (colorized) text via
/// the <see cref="IViewElementFactoryService"/> and is displayed.
/// </remarks>
public sealed class ClassifiedTextRun
{
/// <summary>
/// Creates a new run of classified text.
/// </summary>
/// <param name="classificationTypeName">
/// A name indicating a <see cref="IClassificationType"/> that maps to a format that will be applied to the text.
/// </param>
/// <param name="text">The text rendered by this run.</param>
/// <remarks>
/// Classification types can be platform specific. Only classifications defined in PredefinedClassificationTypeNames
/// are supported cross platform.
/// </remarks>
public ClassifiedTextRun(string classificationTypeName, string text)
{
}
}
- ClassifiedTextElement: A collection of classified text runs.
/// <summary>
/// Represents a block of classified text in an <see cref="IToolTipService"/> <see cref="IToolTipPresenter"/>.
/// </summary>
/// <remarks>
/// Classified text is a span of text with a corresponding classification type name. On
/// <see cref="IToolTipPresenter.StartOrUpdate(ITrackingSpan, System.Collections.Generic.IEnumerable{object})"/>,
/// the classified text is converted to a platform-specific block of runs of formatted (colorized) text via
/// the <see cref="IViewElementFactoryService"/> and is displayed.
/// </remarks>
public sealed class ClassifiedTextElement
{
/// <summary>
/// Creates a new instance of classified text.
/// </summary>
/// <param name="runs">A sequence of zero or more runs of classified text.</param>
public ClassifiedTextElement(params ClassifiedTextRun[] runs)
{
}
}
-
UIElement/ITextView: Objects inheriting from UIElement or ITextView are passed through the conversion service directly without being modified.
-
ITextBuffer/string/object: Objects inheriting from ITextBuffer, string, or object have their string equivalent directly hosted in a new text view and are formatted according to the default ToolTip text properties.
Conversion between ImageMoniker and cross-platform ImageIds can be performed on Windows using the Microsoft.VisualStudio.Core.Imaging.ImageIdExtensions methods in Microsoft.VisualStudio.Language.Intellisense.dll.
On Mac, you can explicitly perform this conversion by constructing an ImageId with the same Guid and int pair.
/// <summary>
/// Extension methods for translating ImageMonikers to and from other types.
/// </summary>
public static class ImageIdExtensions
{
/// <summary>
/// Translates an <see cref="ImageId"/> to an <see cref="ImageMoniker"/>.
/// </summary>
/// <param name="imageId">An image to translate.</param>
/// <returns>The <see cref="ImageMoniker"/> that corresponds to this <see cref="ImageId"/>.</returns>
public static ImageMoniker ToImageMoniker(this ImageId imageId);
/// <summary>
/// Translates an <see cref="ImageMoniker"/> to an <see cref="ImageId"/>.
/// </summary>
/// <param name="imageMoniker">An image to translate.</param>
/// <returns>The <see cref="ImageId"/> that corresponds to this <see cref="ImageId"/>.</returns>
public static ImageId ToImageId(this ImageMoniker imageMoniker);
}