// Copyright (c) 2014 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.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media;
using ICSharpCode.AvalonEdit.Utils;
namespace ICSharpCode.AvalonEdit.Highlighting
{
///
/// Takes a series of highlighting commands and stores them.
/// Later, it can build inline objects (for use with WPF TextBlock) from the commands.
///
///
/// This class is not used in AvalonEdit - but it is useful for someone who wants to put a HighlightedLine
/// into a TextBlock.
/// In SharpDevelop, we use it to provide syntax highlighting inside the search results pad.
///
[Obsolete("Use RichText / RichTextModel instead")]
public sealed class HighlightedInlineBuilder
{
static HighlightingBrush MakeBrush(Brush b)
{
SolidColorBrush scb = b as SolidColorBrush;
if (scb != null)
return new SimpleHighlightingBrush(scb);
else
return null;
}
readonly string text;
List stateChangeOffsets = new List();
List stateChanges = new List();
int GetIndexForOffset(int offset)
{
if (offset < 0 || offset > text.Length)
throw new ArgumentOutOfRangeException("offset");
int index = stateChangeOffsets.BinarySearch(offset);
if (index < 0) {
index = ~index;
if (offset < text.Length) {
stateChanges.Insert(index, stateChanges[index - 1].Clone());
stateChangeOffsets.Insert(index, offset);
}
}
return index;
}
///
/// Creates a new HighlightedInlineBuilder instance.
///
public HighlightedInlineBuilder(string text)
{
if (text == null)
throw new ArgumentNullException("text");
this.text = text;
stateChangeOffsets.Add(0);
stateChanges.Add(new HighlightingColor());
}
///
/// Creates a new HighlightedInlineBuilder instance.
///
public HighlightedInlineBuilder(RichText text)
{
if (text == null)
throw new ArgumentNullException("text");
this.text = text.Text;
stateChangeOffsets.AddRange(text.stateChangeOffsets);
stateChanges.AddRange(text.stateChanges);
}
HighlightedInlineBuilder(string text, List offsets, List states)
{
this.text = text;
stateChangeOffsets = offsets;
stateChanges = states;
}
///
/// Gets the text.
///
public string Text {
get { return text; }
}
///
/// Applies the properties from the HighlightingColor to the specified text segment.
///
public void SetHighlighting(int offset, int length, HighlightingColor color)
{
if (color == null)
throw new ArgumentNullException("color");
if (color.Foreground == null && color.Background == null && color.FontStyle == null && color.FontWeight == null) {
// Optimization: don't split the HighlightingState when we're not changing
// any property. For example, the "Punctuation" color in C# is
// empty by default.
return;
}
int startIndex = GetIndexForOffset(offset);
int endIndex = GetIndexForOffset(offset + length);
for (int i = startIndex; i < endIndex; i++) {
stateChanges[i].MergeWith(color);
}
}
///
/// Sets the foreground brush on the specified text segment.
///
public void SetForeground(int offset, int length, Brush brush)
{
int startIndex = GetIndexForOffset(offset);
int endIndex = GetIndexForOffset(offset + length);
var hbrush = MakeBrush(brush);
for (int i = startIndex; i < endIndex; i++) {
stateChanges[i].Foreground = hbrush;
}
}
///
/// Sets the background brush on the specified text segment.
///
public void SetBackground(int offset, int length, Brush brush)
{
int startIndex = GetIndexForOffset(offset);
int endIndex = GetIndexForOffset(offset + length);
var hbrush = MakeBrush(brush);
for (int i = startIndex; i < endIndex; i++) {
stateChanges[i].Background = hbrush;
}
}
///
/// Sets the font weight on the specified text segment.
///
public void SetFontWeight(int offset, int length, FontWeight weight)
{
int startIndex = GetIndexForOffset(offset);
int endIndex = GetIndexForOffset(offset + length);
for (int i = startIndex; i < endIndex; i++) {
stateChanges[i].FontWeight = weight;
}
}
///
/// Sets the font style on the specified text segment.
///
public void SetFontStyle(int offset, int length, FontStyle style)
{
int startIndex = GetIndexForOffset(offset);
int endIndex = GetIndexForOffset(offset + length);
for (int i = startIndex; i < endIndex; i++) {
stateChanges[i].FontStyle = style;
}
}
///
/// Creates WPF Run instances that can be used for TextBlock.Inlines.
///
public Run[] CreateRuns()
{
return ToRichText().CreateRuns();
}
///
/// Creates a RichText instance.
///
public RichText ToRichText()
{
return new RichText(text, stateChangeOffsets.ToArray(), stateChanges.Select(FreezableHelper.GetFrozenClone).ToArray());
}
///
/// Clones this HighlightedInlineBuilder.
///
public HighlightedInlineBuilder Clone()
{
return new HighlightedInlineBuilder(this.text,
stateChangeOffsets.ToList(),
stateChanges.Select(sc => sc.Clone()).ToList());
}
}
}