diff --git a/Debugger/ILSpy.Debugger/AvalonEdit/ITextMarker.cs b/Debugger/ILSpy.Debugger/AvalonEdit/ITextMarker.cs deleted file mode 100644 index f690f6748..000000000 --- a/Debugger/ILSpy.Debugger/AvalonEdit/ITextMarker.cs +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) -// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) - -using System; -using System.Collections.Generic; -using System.Windows.Media; - -using ICSharpCode.ILSpy.Debugger.Bookmarks; - -namespace ICSharpCode.ILSpy.Debugger.AvalonEdit -{ - /// - /// Represents a text marker. - /// - public interface ITextMarker - { - /// - /// Gets the start offset of the marked text region. - /// - int StartOffset { get; } - - /// - /// Gets the end offset of the marked text region. - /// - int EndOffset { get; } - - /// - /// Gets the length of the marked region. - /// - int Length { get; } - - /// - /// Deletes the text marker. - /// - void Delete(); - - /// - /// Gets whether the text marker was deleted. - /// - bool IsDeleted { get; } - - /// - /// Event that occurs when the text marker is deleted. - /// - event EventHandler Deleted; - - /// - /// Gets/Sets the background color. - /// - Color? BackgroundColor { get; set; } - - /// - /// Gets/Sets the foreground color. - /// - Color? ForegroundColor { get; set; } - - /// - /// Gets/Sets the type of the marker. Use TextMarkerType.None for normal markers. - /// - TextMarkerType MarkerType { get; set; } - - /// - /// Gets/Sets the color of the marker. - /// - Color MarkerColor { get; set; } - - /// - /// Gets/Sets an object with additional data for this text marker. - /// - object Tag { get; set; } - - /// - /// Gets/Sets an object that will be displayed as tooltip in the text editor. - /// - object ToolTip { get; set; } - - /// - /// Gets or sets if the marker is visible or not. - /// - Predicate IsVisible { get; set; } - - /// - /// Gets or sets the bookmark. - /// - IBookmark Bookmark { get; set; } - } - - public enum TextMarkerType - { - /// - /// Use no marker - /// - None, - /// - /// Use squiggly underline marker - /// - SquigglyUnderline - } - - public interface ITextMarkerService - { - /// - /// Creates a new text marker. The text marker will be invisible at first, - /// you need to set one of the Color properties to make it visible. - /// - ITextMarker Create(int startOffset, int length); - - /// - /// Gets the list of text markers. - /// - IEnumerable TextMarkers { get; } - - /// - /// Removes the specified text marker. - /// - void Remove(ITextMarker marker); - - /// - /// Removes all text markers that match the condition. - /// - void RemoveAll(Predicate predicate); - } -} diff --git a/Debugger/ILSpy.Debugger/AvalonEdit/IToolTip.cs b/Debugger/ILSpy.Debugger/AvalonEdit/IToolTip.cs deleted file mode 100644 index bfbddea3c..000000000 --- a/Debugger/ILSpy.Debugger/AvalonEdit/IToolTip.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) -// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) - -using System; -using System.Windows; - -namespace ICSharpCode.ILSpy.Debugger.AvalonEdit -{ - /// - /// Content of text editor tooltip (used as ), - /// specifying whether it should be displayed in a WPF Popup. - /// - internal interface ITooltip - { - /// - /// If true, this ITooltip will be displayed in a WPF Popup. - /// Otherwise it will be displayed in a WPF Tooltip. - /// WPF Popups are (unlike WPF Tooltips) focusable. - /// - bool ShowAsPopup { get; } - - /// - /// Closes this tooltip. - /// - /// True if close request is raised - /// because of mouse click on some SharpDevelop GUI element. - /// True if Close succeeded (that is, can close). False otherwise. - bool Close(bool mouseClick); - - /// - /// Occurs when this tooltip decides to close. - /// - event RoutedEventHandler Closed; - } -} diff --git a/Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs b/Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs deleted file mode 100644 index 9f60a8202..000000000 --- a/Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs +++ /dev/null @@ -1,333 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) -// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) - -using System; -using System.Collections.Generic; -using System.ComponentModel.Composition; -using System.Diagnostics; -using System.Linq; -using System.Windows; -using System.Windows.Input; -using System.Windows.Media; - -using ICSharpCode.AvalonEdit.Editing; -using ICSharpCode.AvalonEdit.Rendering; -using ICSharpCode.AvalonEdit.Utils; -using ICSharpCode.Decompiler; -using ICSharpCode.ILSpy.Debugger.Bookmarks; -using ICSharpCode.ILSpy.Debugger.Services; -using ICSharpCode.NRefactory.CSharp; -using Mono.Cecil; - -namespace ICSharpCode.ILSpy.Debugger.AvalonEdit -{ - [Export("IconMargin"), PartCreationPolicy(CreationPolicy.Shared)] - public class IconBarMargin : AbstractMargin, IDisposable - { - public IconBarMargin() - { - BookmarkManager.Added += delegate { InvalidateVisual(); }; - BookmarkManager.Removed += delegate { InvalidateVisual(); }; - } - - public virtual void Dispose() - { - this.TextView = null; // detach from TextView (will also detach from manager) - } - - /// - protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters) - { - // accept clicks even when clicking on the background - return new PointHitTestResult(this, hitTestParameters.HitPoint); - } - - /// - protected override Size MeasureOverride(Size availableSize) - { - return new Size(18, 0); - } - - protected override void OnRender(DrawingContext drawingContext) - { - Size renderSize = this.RenderSize; - drawingContext.DrawRectangle(SystemColors.ControlBrush, null, - new Rect(0, 0, renderSize.Width, renderSize.Height)); - drawingContext.DrawLine(new Pen(SystemColors.ControlDarkBrush, 1), - new Point(renderSize.Width - 0.5, 0), - new Point(renderSize.Width - 0.5, renderSize.Height)); - - TextView textView = this.TextView; - if (textView != null && textView.VisualLinesValid) { - // create a dictionary line number => first bookmark - Dictionary bookmarkDict = new Dictionary(); - foreach (var bm in BookmarkManager.Bookmarks) { - if (DebugData.DecompiledMemberReferences == null || DebugData.DecompiledMemberReferences.Count == 0 || - !DebugData.DecompiledMemberReferences.ContainsKey(bm.MemberReference.MetadataToken.ToInt32())) - continue; - - int line = bm.LineNumber; - BookmarkBase existingBookmark; - if (!bookmarkDict.TryGetValue(line, out existingBookmark) || bm.ZOrder > existingBookmark.ZOrder) - bookmarkDict[line] = bm; - } - Size pixelSize = PixelSnapHelpers.GetPixelSize(this); - foreach (VisualLine line in textView.VisualLines) { - int lineNumber = line.FirstDocumentLine.LineNumber; - BookmarkBase bm; - if (bookmarkDict.TryGetValue(lineNumber, out bm)) { - Rect rect = new Rect(0, PixelSnapHelpers.Round(line.VisualTop - textView.VerticalOffset, pixelSize.Height), 16, 16); - if (dragDropBookmark == bm && dragStarted) - drawingContext.PushOpacity(0.5); - drawingContext.DrawImage(bm.Image, rect); - if (dragDropBookmark == bm && dragStarted) - drawingContext.Pop(); - } - } - if (dragDropBookmark != null && dragStarted) { - Rect rect = new Rect(0, PixelSnapHelpers.Round(dragDropCurrentPoint - 8, pixelSize.Height), 16, 16); - drawingContext.DrawImage(dragDropBookmark.Image, rect); - } - } - } - - IBookmark dragDropBookmark; // bookmark being dragged (!=null if drag'n'drop is active) - double dragDropStartPoint; - double dragDropCurrentPoint; - bool dragStarted; // whether drag'n'drop operation has started (mouse was moved minimum distance) - - protected override void OnMouseDown(MouseButtonEventArgs e) - { - base.OnMouseDown(e); - int line = GetLineFromMousePosition(e); - if (!e.Handled && line > 0) { - IBookmark bm = GetBookmarkFromLine(line); - if (bm != null) { - bm.MouseDown(e); - if (!e.Handled) { - if (e.ChangedButton == MouseButton.Left && bm.CanDragDrop && CaptureMouse()) { - StartDragDrop(bm, e); - e.Handled = true; - } - } - } - } - // don't allow selecting text through the IconBarMargin - if (e.ChangedButton == MouseButton.Left) - e.Handled = true; - } - - BookmarkBase GetBookmarkFromLine(int line) - { - BookmarkBase result = null; - foreach (BookmarkBase bm in BookmarkManager.Bookmarks) { - if (bm.LineNumber == line && - DebugData.DecompiledMemberReferences != null && DebugData.DecompiledMemberReferences.ContainsKey(bm.MemberReference.MetadataToken.ToInt32())) { - if (result == null || bm.ZOrder > result.ZOrder) - result = bm; - } - } - return result; - } - - protected override void OnLostMouseCapture(MouseEventArgs e) - { - CancelDragDrop(); - base.OnLostMouseCapture(e); - } - - void StartDragDrop(IBookmark bm, MouseEventArgs e) - { - dragDropBookmark = bm; - dragDropStartPoint = dragDropCurrentPoint = e.GetPosition(this).Y; - if (TextView != null) { - TextArea area = TextView.Services.GetService(typeof(TextArea)) as TextArea; - if (area != null) - area.PreviewKeyDown += TextArea_PreviewKeyDown; - } - } - - void CancelDragDrop() - { - if (dragDropBookmark != null) { - dragDropBookmark = null; - dragStarted = false; - if (TextView != null) { - TextArea area = TextView.Services.GetService(typeof(TextArea)) as TextArea; - if (area != null) - area.PreviewKeyDown -= TextArea_PreviewKeyDown; - } - ReleaseMouseCapture(); - InvalidateVisual(); - } - } - - void TextArea_PreviewKeyDown(object sender, KeyEventArgs e) - { - // any key press cancels drag'n'drop - CancelDragDrop(); - if (e.Key == Key.Escape) - e.Handled = true; - } - - int GetLineFromMousePosition(MouseEventArgs e) - { - TextView textView = this.TextView; - if (textView == null) - return 0; - VisualLine vl = textView.GetVisualLineFromVisualTop(e.GetPosition(textView).Y + textView.ScrollOffset.Y); - if (vl == null) - return 0; - return vl.FirstDocumentLine.LineNumber; - } - - protected override void OnMouseMove(MouseEventArgs e) - { - base.OnMouseMove(e); - if (dragDropBookmark != null) { - dragDropCurrentPoint = e.GetPosition(this).Y; - if (Math.Abs(dragDropCurrentPoint - dragDropStartPoint) > SystemParameters.MinimumVerticalDragDistance) - dragStarted = true; - InvalidateVisual(); - } - - BreakpointBookmark bm = BookmarkManager.Bookmarks.Find( - b => DebugData.CodeMappings != null && DebugData.CodeMappings.ContainsKey(b.MemberReference.MetadataToken.ToInt32()) && - b.LineNumber == GetLineFromMousePosition(e) - && b is BreakpointBookmark) as BreakpointBookmark; - - this.ToolTip = (bm != null) ? bm.Tooltip : null; - } - - protected override void OnMouseUp(MouseButtonEventArgs e) - { - base.OnMouseUp(e); - int line = GetLineFromMousePosition(e); - if (!e.Handled && dragDropBookmark != null) { - if (dragStarted) { - if (line != 0) - dragDropBookmark.Drop(line); - e.Handled = true; - } - CancelDragDrop(); - } - if (!e.Handled && line != 0) { - BookmarkBase bm = GetBookmarkFromLine(line); - if (bm != null) { - bm.MouseUp(e); - - if (bm.CanToggle) { - BookmarkManager.RemoveMark(bm); - InvalidateVisual(); - } - - if (e.Handled) - return; - } - if (e.ChangedButton == MouseButton.Left) { - if (DebugData.CodeMappings != null && DebugData.CodeMappings.Count > 0) { - - // check if the codemappings exists for this line - var storage = DebugData.CodeMappings; - int token = 0; - foreach (var key in storage.Keys) { - var instruction = storage[key].GetInstructionByLineNumber(line, out token); - - if (instruction == null) { - continue; - } - - // no bookmark on the line: create a new breakpoint - DebuggerService.ToggleBreakpointAt( - DebugData.DecompiledMemberReferences[key], - line, - instruction.ILInstructionOffset, - DebugData.Language); - break; - } - - if (token == 0) { - MessageBox.Show(string.Format("Missing code mappings at line {0}.", line), - "Code mappings", MessageBoxButton.OK, MessageBoxImage.Information); - return; - } - } - } - InvalidateVisual(); - } - } - - public void SyncBookmarks() - { - var storage = DebugData.CodeMappings; - if (storage == null || storage.Count == 0) - return; - - //remove existing bookmarks and create new ones - List newBookmarks = new List(); - for (int i = BookmarkManager.Bookmarks.Count - 1; i >= 0; --i) { - var breakpoint = BookmarkManager.Bookmarks[i] as BreakpointBookmark; - if (breakpoint == null) - continue; - - var key = breakpoint.MemberReference.MetadataToken.ToInt32(); - if (!storage.ContainsKey(key)) - continue; - - var member = DebugData.DecompiledMemberReferences[key]; - - bool isMatch; - SourceCodeMapping map = storage[key].GetInstructionByTokenAndOffset( - member.MetadataToken.ToInt32(), breakpoint.ILRange.From, out isMatch); - - if (map != null) { - newBookmarks.Add(new BreakpointBookmark( - member, new AstLocation(map.SourceCodeLine, 0), - map.ILInstructionOffset, BreakpointAction.Break, DebugData.Language)); - - BookmarkManager.RemoveMark(breakpoint); - } - } - - newBookmarks.ForEach(m => BookmarkManager.AddMark(m)); - - SyncCurrentLineBookmark(); - } - - void SyncCurrentLineBookmark() - { - // checks - if (CurrentLineBookmark.Instance == null) - return; - - var oldMappings = DebugData.OldCodeMappings; - var newMappings = DebugData.CodeMappings; - - if (oldMappings == null || newMappings == null) - return; - - // 1. Save it's data - int line = CurrentLineBookmark.Instance.LineNumber; - var markerType = CurrentLineBookmark.Instance.MemberReference; - - if (!oldMappings.ContainsKey(markerType.MetadataToken.ToInt32()) || !newMappings.ContainsKey(markerType.MetadataToken.ToInt32())) - return; - - // 2. Remove it - CurrentLineBookmark.Remove(); - - // 3. map the marker line - int token; - var instruction = oldMappings[markerType.MetadataToken.ToInt32()].GetInstructionByLineNumber(line, out token); - if (instruction == null) - return; - - MemberReference memberReference; - int newline; - if (newMappings[markerType.MetadataToken.ToInt32()].GetInstructionByTokenAndOffset(token, instruction.ILInstructionOffset.From, out memberReference, out newline)) { - // 4. create breakpoint for new languages - CurrentLineBookmark.SetPosition(memberReference, newline, 0, newline, 0); - } - } - } -} \ No newline at end of file diff --git a/Debugger/ILSpy.Debugger/AvalonEdit/TextEditorWeakEventManager.cs b/Debugger/ILSpy.Debugger/AvalonEdit/TextEditorWeakEventManager.cs deleted file mode 100644 index 1ac80f7d5..000000000 --- a/Debugger/ILSpy.Debugger/AvalonEdit/TextEditorWeakEventManager.cs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Windows; -using ICSharpCode.AvalonEdit; -using ICSharpCode.AvalonEdit.Utils; - -namespace ICSharpCode.ILSpy.Debugger.AvalonEdit -{ - public static class TextEditorWeakEventManager - { - public sealed class MouseHover : WeakEventManagerBase - { - protected override void StopListening(TextEditor source) - { - source.MouseHover -= DeliverEvent; - } - - protected override void StartListening(TextEditor source) - { - source.MouseHover += DeliverEvent; - } - } - - public sealed class MouseHoverStopped : WeakEventManagerBase - { - protected override void StopListening(TextEditor source) - { - source.MouseHoverStopped -= DeliverEvent; - } - - protected override void StartListening(TextEditor source) - { - source.MouseHoverStopped += DeliverEvent; - } - } - - public sealed class MouseDown : WeakEventManagerBase - { - protected override void StopListening(TextEditor source) - { - source.MouseDown -= DeliverEvent; - } - - protected override void StartListening(TextEditor source) - { - source.MouseDown += DeliverEvent; - } - } - } -} diff --git a/Debugger/ILSpy.Debugger/AvalonEdit/TextMarkerService.cs b/Debugger/ILSpy.Debugger/AvalonEdit/TextMarkerService.cs deleted file mode 100644 index 8c6b89525..000000000 --- a/Debugger/ILSpy.Debugger/AvalonEdit/TextMarkerService.cs +++ /dev/null @@ -1,319 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) -// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) - -using System; -using System.Collections.Generic; -using System.ComponentModel.Composition; -using System.Linq; -using System.Windows; -using System.Windows.Media; -using System.Windows.Threading; - -using ICSharpCode.AvalonEdit; -using ICSharpCode.AvalonEdit.Document; -using ICSharpCode.AvalonEdit.Rendering; -using ICSharpCode.ILSpy.Debugger.Bookmarks; - -namespace ICSharpCode.ILSpy.Debugger.AvalonEdit -{ - /// - /// Handles the text markers for a code editor. - /// - [Export("TextMarkerService"), PartCreationPolicy(CreationPolicy.Shared)] - public sealed class TextMarkerService : DocumentColorizingTransformer, IBackgroundRenderer, ITextMarkerService - { - TextEditor codeEditor; - - TextSegmentCollection markers = new TextSegmentCollection(); - - public TextMarkerService() - { - BookmarkManager.Added += new BookmarkEventHandler(BookmarkManager_Added); - BookmarkManager.Removed += new BookmarkEventHandler(BookmarkManager_Removed); - } - - public TextEditor CodeEditor { - get { return codeEditor; } - set { codeEditor = value; } - } - - void BookmarkManager_Removed(object sender, BookmarkEventArgs e) - { - if (e.Bookmark is BreakpointBookmark) { - var bm = (MarkerBookmark)e.Bookmark; - Remove(bm.Marker); - } - - if (e.Bookmark is CurrentLineBookmark) { - RemoveAll(m => m.Bookmark is CurrentLineBookmark); - } - } - - void BookmarkManager_Added(object sender, BookmarkEventArgs e) - { - if (e.Bookmark is MarkerBookmark) { - var bm = (MarkerBookmark)e.Bookmark; - // add bookmark for the current type - if (bm.LineNumber < codeEditor.Document.LineCount) { - DocumentLine line = codeEditor.Document.GetLineByNumber(bm.LineNumber); - bm.CreateMarker(this, line.Offset, line.Length); - } - } - } - - #region ITextMarkerService - public ITextMarker Create(int startOffset, int length) - { - int textLength = codeEditor.TextArea.TextView.Document.TextLength; - if (startOffset < 0 || startOffset > textLength) - throw new ArgumentOutOfRangeException("startOffset", startOffset, "Value must be between 0 and " + textLength); - if (length < 0 || startOffset + length > textLength) - throw new ArgumentOutOfRangeException("length", length, "length must not be negative and startOffset+length must not be after the end of the document"); - - TextMarker m = new TextMarker(this, startOffset, length); - markers.Add(m); - // no need to mark segment for redraw: the text marker is invisible until a property is set - return m; - } - - public IEnumerable GetMarkersAtOffset(int offset) - { - return markers.FindSegmentsContaining(offset); - } - - public IEnumerable TextMarkers { - get { return markers; } - } - - public void RemoveAll(Predicate predicate) - { - if (predicate == null) - throw new ArgumentNullException("predicate"); - foreach (TextMarker m in markers.ToArray()) { - if (predicate(m)) - Remove(m); - } - } - - public void Remove(ITextMarker marker) - { - if (marker == null) - return; - - TextMarker m = marker as TextMarker; - if (markers.Remove(m)) { - Redraw(m); - m.OnDeleted(); - } - } - - /// - /// Redraws the specified text segment. - /// - public void Redraw(ISegment segment) - { - codeEditor.TextArea.TextView.Redraw(segment, DispatcherPriority.Normal); - } - #endregion - - #region DocumentColorizingTransformer - protected override void ColorizeLine(DocumentLine line) - { - if (markers == null) - return; - int lineStart = line.Offset; - int lineEnd = lineStart + line.Length; - foreach (TextMarker marker in markers.FindOverlappingSegments(lineStart, line.Length).Reverse()) { - if (!marker.IsVisible(marker.Bookmark)) - continue; - - Brush foregroundBrush = null; - if (marker.ForegroundColor != null) { - foregroundBrush = new SolidColorBrush(marker.ForegroundColor.Value); - foregroundBrush.Freeze(); - } - ChangeLinePart( - Math.Max(marker.StartOffset, lineStart), - Math.Min(marker.EndOffset, lineEnd), - element => { - if (foregroundBrush != null) { - element.TextRunProperties.SetForegroundBrush(foregroundBrush); - } - } - ); - } - } - #endregion - - #region IBackgroundRenderer - public KnownLayer Layer { - get { - // draw behind selection - return KnownLayer.Selection; - } - } - - public void Draw(TextView textView, DrawingContext drawingContext) - { - if (textView == null) - throw new ArgumentNullException("textView"); - if (drawingContext == null) - throw new ArgumentNullException("drawingContext"); - if (markers == null || !textView.VisualLinesValid) - return; - var visualLines = textView.VisualLines; - if (visualLines.Count == 0) - return; - int viewStart = visualLines.First().FirstDocumentLine.Offset; - int viewEnd = visualLines.Last().LastDocumentLine.Offset + visualLines.Last().LastDocumentLine.Length; - foreach (TextMarker marker in markers.FindOverlappingSegments(viewStart, viewEnd - viewStart).Reverse()) { - if (!marker.IsVisible(marker.Bookmark)) - continue; - - if (marker.BackgroundColor != null) { - BackgroundGeometryBuilder geoBuilder = new BackgroundGeometryBuilder(); - geoBuilder.AlignToWholePixels = true; - geoBuilder.CornerRadius = 3; - geoBuilder.AddSegment(textView, marker); - Geometry geometry = geoBuilder.CreateGeometry(); - if (geometry != null) { - Color color = marker.BackgroundColor.Value; - SolidColorBrush brush = new SolidColorBrush(color); - brush.Freeze(); - drawingContext.DrawGeometry(brush, null, geometry); - } - } - if (marker.MarkerType != TextMarkerType.None) { - foreach (Rect r in BackgroundGeometryBuilder.GetRectsForSegment(textView, marker)) { - Point startPoint = r.BottomLeft; - Point endPoint = r.BottomRight; - - Pen usedPen = new Pen(new SolidColorBrush(marker.MarkerColor), 1); - usedPen.Freeze(); - switch (marker.MarkerType) { - case TextMarkerType.SquigglyUnderline: - double offset = 2.5; - - int count = Math.Max((int)((endPoint.X - startPoint.X) / offset) + 1, 4); - - StreamGeometry geometry = new StreamGeometry(); - - using (StreamGeometryContext ctx = geometry.Open()) { - ctx.BeginFigure(startPoint, false, false); - ctx.PolyLineTo(CreatePoints(startPoint, endPoint, offset, count).ToArray(), true, false); - } - - geometry.Freeze(); - - drawingContext.DrawGeometry(Brushes.Transparent, usedPen, geometry); - break; - } - } - } - } - } - - IEnumerable CreatePoints(Point start, Point end, double offset, int count) - { - for (int i = 0; i < count; i++) - yield return new Point(start.X + i * offset, start.Y - ((i + 1) % 2 == 0 ? offset : 0)); - } - #endregion - } - - sealed class TextMarker : TextSegment, ITextMarker - { - readonly TextMarkerService service; - - public TextMarker(TextMarkerService service, int startOffset, int length) - { - if (service == null) - throw new ArgumentNullException("service"); - this.service = service; - this.StartOffset = startOffset; - this.Length = length; - this.markerType = TextMarkerType.None; - } - - public event EventHandler Deleted; - - public bool IsDeleted { - get { return !this.IsConnectedToCollection; } - } - - public void Delete() - { - service.Remove(this); - } - - internal void OnDeleted() - { - if (Deleted != null) - Deleted(this, EventArgs.Empty); - } - - void Redraw() - { - service.Redraw(this); - } - - Color? backgroundColor; - - public Color? BackgroundColor { - get { return backgroundColor; } - set { - if (backgroundColor != value) { - backgroundColor = value; - Redraw(); - } - } - } - - Color? foregroundColor; - - public Color? ForegroundColor { - get { return foregroundColor; } - set { - if (foregroundColor != value) { - foregroundColor = value; - Redraw(); - } - } - } - - public object Tag { get; set; } - - TextMarkerType markerType; - - public TextMarkerType MarkerType { - get { return markerType; } - set { - if (markerType != value) { - markerType = value; - Redraw(); - } - } - } - - Color markerColor; - - public Color MarkerColor { - get { return markerColor; } - set { - if (markerColor != value) { - markerColor = value; - Redraw(); - } - } - - } - /// - public object ToolTip { get; set; } - - /// - public Predicate IsVisible { get; set; } - - /// - public IBookmark Bookmark { get; set; } - } -}