/// <summary> /// Occurs when a menu item is clicked. /// </summary> /// <param name="sender">The sender of the event.</param> /// <param name="e">The <see cref="RoutedEventArgs"/> that contains data related to this event.</param> private void OnRemoveNote(object sender, RoutedEventArgs e) { MenuItem item = (MenuItem)sender; // Get the tag range TagSnapshotRange <IntraTextNoteTag> tagRange = (TagSnapshotRange <IntraTextNoteTag>)item.Tag; // Get the tagger from the code document ICodeDocument document = tagRange.SnapshotRange.Snapshot.Document as ICodeDocument; if (document != null) { IntraTextNoteTagger tagger = null; if (document.Properties.TryGetValue(typeof(IntraTextNoteTagger), out tagger)) { // Try and find the tag version range that contains the tag TagVersionRange <IIntraTextSpacerTag> tagVersionRange = tagger[tagRange.Tag]; if (tagVersionRange != null) { // Remove the tag version range from the tagger tagger.Remove(tagVersionRange); } } } }
///////////////////////////////////////////////////////////////////////////////////////////////////// // PUBLIC PROCEDURES ///////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Adds an adornment to the <see cref="AdornmentLayer"/>. /// </summary> /// <param name="viewLine">The current <see cref="ITextViewLine"/> being examined.</param> /// <param name="tagRange">The <see cref="ITag"/> and the range it covers.</param> protected override void AddAdornment(ITextViewLine viewLine, TagSnapshotRange <IntraLineViewportTag> tagRange) { // Determine the bounds var bounds = this.GetAdornmentBounds(tagRange.Tag); var charBounds = viewLine.GetCharacterBounds(tagRange.SnapshotRange.StartOffset); bounds.Y = charBounds.Bottom; // See if a cached version of the element for the tag is available var element = this.GetCachedElement(tagRange.Tag); if (element == null) { // Create the element element = new AdornmentElement(); } // Update the size element.Width = bounds.Width; element.Height = bounds.Height; element.Tag = tagRange.Tag; // Add the adornment this.AdornmentLayer.AddAdornment(AdornmentChangeReason.Other, element, bounds.Location, tagRange.Tag.Key, OnAdornmentRemoved); }
///////////////////////////////////////////////////////////////////////////////////////////////////// // NON-PUBLIC PROCEDURES ///////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Changes the status of the specified note tag. /// </summary> /// <param name="tagRange">The tag range.</param> /// <param name="status">The new status.</param> private void ChangeNoteStatus(TagSnapshotRange <IntraTextNoteTag> tagRange, ReviewStatus status) { // Get the tagger from the code document ICodeDocument document = tagRange.SnapshotRange.Snapshot.Document as ICodeDocument; if (document != null) { IntraTextNoteTagger tagger = null; if (document.Properties.TryGetValue(typeof(IntraTextNoteTagger), out tagger)) { // Change the tag's status and raise an event so the UI knows to update tagRange.Tag.Status = status; tagger.RaiseTagsChanged(new TagsChangedEventArgs(tagRange.SnapshotRange)); } } }
public override FrameworkElement CreateGlyph(IEditorViewLine viewLine, TagSnapshotRange<IIndicatorTag> tagRange, Rect bounds) { var foreground = new SolidColorBrush(Color.FromArgb(0xff, 0xff, 0x40, 0x00)); var background = new SolidColorBrush(Color.FromArgb(0xff, 0xff, 0xbb, 0xbb)); foreground.Freeze(); background.Freeze(); var diameter = Math.Max(8.0, Math.Min(13, Math.Round(Math.Min(bounds.Width, bounds.Height) - 2.0))); var grid = new Grid {Width = diameter, Height = diameter}; var outerBorder = new Ellipse() { Fill = background, Stroke = foreground, StrokeThickness = 1.0, }; grid.Children.Add(outerBorder); return grid; }
///////////////////////////////////////////////////////////////////////////////////////////////////// // PUBLIC PROCEDURES ///////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Adds an adornment to the <see cref="AdornmentLayer"/>. /// </summary> /// <param name="reason">An <see cref="AdornmentChangeReason"/> indicating the add reason.</param> /// <param name="viewLine">The current <see cref="ITextViewLine"/> being examined.</param> /// <param name="tagRange">The <see cref="ITag"/> and the range it covers.</param> /// <param name="bounds">The text bounds in which to render an adornment.</param> protected override void AddAdornment(AdornmentChangeReason reason, ITextViewLine viewLine, TagSnapshotRange <IntraTextNoteTag> tagRange, TextBounds bounds) { // Create the adornment var image = new DynamicImage(); image.Width = 16; image.Height = 16; image.SnapsToDevicePixels = true; image.Source = new BitmapImage(new Uri("/Images/Icons/Notes16.png", UriKind.Relative)); image.Stretch = Stretch.Fill; // Create a popup button PopupButton button = new PopupButton(); button.Content = image; button.Cursor = Cursors.Arrow; button.DisplayMode = PopupButtonDisplayMode.Merged; button.Focusable = false; button.IsTabStop = false; button.IsTransparencyModeEnabled = true; button.Margin = new Thickness(0); button.Padding = new Thickness(-1); button.ToolTip = new HtmlContentProvider(String.Format("<span style=\"color: green;\">{0}</span><br/>Created at <b>{1}</b> by <span style=\"color: blue;\">{2}</span><br/>Status: <b>{3}</b>", tagRange.Tag.Message, tagRange.Tag.Created.ToShortTimeString(), tagRange.Tag.Author, tagRange.Tag.Status)).GetContent(); // Add a context menu ContextMenu contextMenu = new ContextMenu(); button.PopupMenu = contextMenu; MenuItem removeItem = new MenuItem(); removeItem.Header = "Remove Note"; removeItem.Tag = tagRange; removeItem.Click += new RoutedEventHandler(OnRemoveNote); contextMenu.Items.Add(removeItem); contextMenu.Items.Add(new Separator()); MenuItem pendingItem = new MenuItem(); pendingItem.Header = "Mark as Pending"; pendingItem.IsChecked = (tagRange.Tag.Status == ReviewStatus.Pending); pendingItem.Tag = tagRange; pendingItem.Click += new RoutedEventHandler(OnMarkNoteAsPending); contextMenu.Items.Add(pendingItem); MenuItem acceptedItem = new MenuItem(); acceptedItem.Header = "Mark as Accepted"; acceptedItem.IsChecked = (tagRange.Tag.Status == ReviewStatus.Accepted); acceptedItem.Tag = tagRange; acceptedItem.Click += new RoutedEventHandler(OnMarkNoteAsAccpeted); contextMenu.Items.Add(acceptedItem); MenuItem rejectedItem = new MenuItem(); rejectedItem.Header = "Mark as Rejected"; rejectedItem.IsChecked = (tagRange.Tag.Status == ReviewStatus.Rejected); rejectedItem.Tag = tagRange; rejectedItem.Click += new RoutedEventHandler(OnMarkNoteAsRejected); contextMenu.Items.Add(rejectedItem); // Get the location Point location = new Point(Math.Round(bounds.Left) + 1, Math.Round(bounds.Top + (bounds.Height - tagRange.Tag.Size.Height) / 2)); // Add the adornment to the layer this.AdornmentLayer.AddAdornment(reason, button, location, tagRange.Tag.Key, null); }
/// <summary> /// Draws the indicator's glyph in an editor view margin. /// </summary> /// <param name="context">The <see cref="TextViewDrawContext"/> to use for rendering.</param> /// <param name="viewLine">The <see cref="ITextViewLine"/> for which the glyph is rendered.</param> /// <param name="tagRange">The <see cref="ITag"/> and the range it covers.</param> /// <param name="bounds">The bounds in which the indicator will be rendered.</param> public override void DrawGlyph(TextViewDrawContext context, ITextViewLine viewLine, TagSnapshotRange <IIndicatorTag> tagRange, Rect bounds) { var diameter = Math.Max(8.0, Math.Min(13, Math.Round(Math.Min(bounds.Width, bounds.Height) - 2.0))); var x = bounds.X + (bounds.Width - diameter) / 2.0; var y = bounds.Y + (bounds.Height - diameter) / 2.0; context.FillEllipse(new Rect(x, y, diameter, diameter), Color.FromArgb(0xff, 0x8a, 0xf3, 0x82)); context.DrawEllipse(new Rect(x, y, diameter, diameter), Color.FromArgb(0xff, 0x00, 0x40, 0x00), LineKind.Solid, 1); }
///////////////////////////////////////////////////////////////////////////////////////////////////// // PUBLIC PROCEDURES ///////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Adds an adornment to the <see cref="AdornmentLayer"/>. /// </summary> /// <param name="reason">An <see cref="AdornmentChangeReason"/> indicating the add reason.</param> /// <param name="viewLine">The current <see cref="ITextViewLine"/> being examined.</param> /// <param name="tagRange">The <see cref="ITag"/> and the range it covers.</param> /// <param name="bounds">The text bounds in which to render an adornment.</param> protected override void AddAdornment(AdornmentChangeReason reason, ITextViewLine viewLine, TagSnapshotRange <ColorPreviewTag> tagRange, TextBounds bounds) { // Round off the bounds to integers to help ensure crispness var adornmentBounds = new Rect(Math.Round(bounds.Left, MidpointRounding.AwayFromZero), Math.Round(bounds.Top, MidpointRounding.AwayFromZero), Math.Round(bounds.Width, MidpointRounding.AwayFromZero), Math.Round(bounds.Height, MidpointRounding.AwayFromZero)); // Add the adornment to the layer this.AdornmentLayer.AddAdornment(reason, OnDrawHighlightAdornment, adornmentBounds, tagRange.Tag, viewLine, tagRange.SnapshotRange, TextRangeTrackingModes.ExpandBothEdges, null); }