Consider border thickness when rounding to pixel boundaries (#38).

This commit is contained in:
Daniel Grunwald 2015-05-03 16:45:07 +02:00
Родитель 532cab08b8
Коммит 6f76dd9ee7
11 изменённых файлов: 63 добавлений и 24 удалений

Просмотреть файл

@ -16,7 +16,7 @@
<TreatWarningsAsErrors>False</TreatWarningsAsErrors>
<IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
<WarningLevel>4</WarningLevel>
<PlatformTarget>AnyCPU</PlatformTarget>
<PlatformTarget>x86</PlatformTarget>
<BaseAddress>4194304</BaseAddress>
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
@ -40,8 +40,8 @@
<Optimize>False</Optimize>
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
<BaseIntermediateOutputPath>obj\</BaseIntermediateOutputPath>
<DefineDebug>True</DefineDebug>
<DefineTrace>True</DefineTrace>
<DefineDebug>True</DefineDebug>
<DefineTrace>True</DefineTrace>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<OutputPath>bin\Release\</OutputPath>
@ -50,7 +50,7 @@
<Optimize>True</Optimize>
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
<BaseIntermediateOutputPath>obj\</BaseIntermediateOutputPath>
<DefineTrace>True</DefineTrace>
<DefineTrace>True</DefineTrace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\NRefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj" Condition="$(DefineConstants.Contains('NREFACTORY'))">

Просмотреть файл

@ -60,6 +60,8 @@ namespace ICSharpCode.AvalonEdit.Sample
#endif
propertyGridComboBox.SelectedIndex = 2;
//textEditor.TextArea.SelectionBorder = null;
//textEditor.SyntaxHighlighting = HighlightingManager.Instance.GetDefinition("C#");
//textEditor.SyntaxHighlighting = customHighlighting;
// initial highlighting now set by XAML

Просмотреть файл

@ -21,6 +21,7 @@ using System.Windows;
using System.Windows.Media;
using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.AvalonEdit.Utils;
namespace ICSharpCode.AvalonEdit.Editing
{
@ -52,8 +53,11 @@ namespace ICSharpCode.AvalonEdit.Editing
{
base.OnRender(drawingContext);
var selectionBorder = textArea.SelectionBorder;
BackgroundGeometryBuilder geoBuilder = new BackgroundGeometryBuilder();
geoBuilder.AlignToMiddleOfPixels = true;
geoBuilder.AlignToWholePixels = true;
geoBuilder.BorderThickness = selectionBorder != null ? selectionBorder.Thickness : 0;
geoBuilder.ExtendToFullWidthAtLineEnd = textArea.Selection.EnableVirtualSpace;
geoBuilder.CornerRadius = textArea.SelectionCornerRadius;
foreach (var segment in textArea.Selection.Segments) {
@ -61,7 +65,7 @@ namespace ICSharpCode.AvalonEdit.Editing
}
Geometry geometry = geoBuilder.CreateGeometry();
if (geometry != null) {
drawingContext.DrawGeometry(textArea.SelectionBrush, textArea.SelectionBorder, geometry);
drawingContext.DrawGeometry(textArea.SelectionBrush, selectionBorder, geometry);
}
}
}

Просмотреть файл

@ -470,7 +470,7 @@ namespace ICSharpCode.AvalonEdit.Editing
DependencyProperty.Register("SelectionForeground", typeof(Brush), typeof(TextArea));
/// <summary>
/// Gets/Sets the foreground brush used selected text.
/// Gets/Sets the foreground brush used for selected text.
/// </summary>
public Brush SelectionForeground {
get { return (Brush)GetValue(SelectionForegroundProperty); }
@ -484,7 +484,7 @@ namespace ICSharpCode.AvalonEdit.Editing
DependencyProperty.Register("SelectionBorder", typeof(Pen), typeof(TextArea));
/// <summary>
/// Gets/Sets the background brush used for the selection.
/// Gets/Sets the pen used for the border of the selection.
/// </summary>
public Pen SelectionBorder {
get { return (Pen)GetValue(SelectionBorderProperty); }

Просмотреть файл

@ -42,6 +42,7 @@
<AssemblyOriginatorKeyFile>..\..\NRefactory\ICSharpCode.NRefactory.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DefineConstants>DEBUG;$(DefineConstants)</DefineConstants>
<OutputPath>bin\Debug\</OutputPath>
<DocumentationFile>bin\Debug\ICSharpCode.AvalonEdit.xml</DocumentationFile>
<DebugSymbols>true</DebugSymbols>

Просмотреть файл

@ -54,7 +54,7 @@ using System.Windows.Markup;
[assembly: AssemblyCompany("ic#code")]
[assembly: AssemblyProduct("SharpDevelop")]
[assembly: AssemblyCopyright("2000-2014 AlphaSierraPapa for the SharpDevelop Team")]
[assembly: AssemblyVersion("5.0.1")]
[assembly: AssemblyVersion("5.0.3")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: XmlnsPrefix("http://icsharpcode.net/sharpdevelop/avalonedit", "avalonedit")]

Просмотреть файл

@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Windows;
using System.Windows.Controls.Primitives;
@ -46,14 +47,41 @@ namespace ICSharpCode.AvalonEdit.Rendering
}
/// <summary>
/// Gets/Sets whether to align the geometry to whole pixels.
/// Gets/Sets whether to align to whole pixels.
///
/// If BorderThickness is set to 0, the geometry is aligned to whole pixels.
/// If BorderThickness is set to a non-zero value, the outer edge of the border is aligned
/// to whole pixels.
///
/// The default value is <c>false</c>.
/// </summary>
public bool AlignToWholePixels { get; set; }
/// <summary>
/// Gets/sets the border thickness.
///
/// This property only has an effect if <c>AlignToWholePixels</c> is enabled.
/// When using the resulting geometry to paint a border, set this property to the border thickness.
/// Otherwise, leave the property set to the default value <c>0</c>.
/// </summary>
public double BorderThickness { get; set; }
bool alignToMiddleOfPixels;
/// <summary>
/// Gets/Sets whether to align the geometry to the middle of pixels.
/// </summary>
public bool AlignToMiddleOfPixels { get; set; }
[Obsolete("Use the AlignToWholePixels and BorderThickness properties instead. "
+ "Setting AlignToWholePixels=true and setting the BorderThickness to the pixel size "
+ "is equivalent to aligning the geometry to the middle of pixels.")]
public bool AlignToMiddleOfPixels {
get {
return alignToMiddleOfPixels;
}
set {
alignToMiddleOfPixels = value;
}
}
/// <summary>
/// Gets/Sets whether to extend the rectangles to full width at line end.
@ -96,17 +124,19 @@ namespace ICSharpCode.AvalonEdit.Rendering
void AddRectangle(Size pixelSize, Rect r)
{
if (AlignToWholePixels) {
AddRectangle(PixelSnapHelpers.Round(r.Left, pixelSize.Width),
PixelSnapHelpers.Round(r.Top + 1, pixelSize.Height),
PixelSnapHelpers.Round(r.Right, pixelSize.Width),
PixelSnapHelpers.Round(r.Bottom + 1, pixelSize.Height));
} else if (AlignToMiddleOfPixels) {
double halfBorder = 0.5 * BorderThickness;
AddRectangle(PixelSnapHelpers.Round(r.Left - halfBorder, pixelSize.Width) + halfBorder,
PixelSnapHelpers.Round(r.Top - halfBorder, pixelSize.Height) + halfBorder,
PixelSnapHelpers.Round(r.Right + halfBorder, pixelSize.Width) - halfBorder,
PixelSnapHelpers.Round(r.Bottom + halfBorder, pixelSize.Height) - halfBorder);
//Debug.WriteLine(r.ToString() + " -> " + new Rect(lastLeft, lastTop, lastRight-lastLeft, lastBottom-lastTop).ToString());
} else if (alignToMiddleOfPixels) {
AddRectangle(PixelSnapHelpers.PixelAlign(r.Left, pixelSize.Width),
PixelSnapHelpers.PixelAlign(r.Top + 1, pixelSize.Height),
PixelSnapHelpers.PixelAlign(r.Top, pixelSize.Height),
PixelSnapHelpers.PixelAlign(r.Right, pixelSize.Width),
PixelSnapHelpers.PixelAlign(r.Bottom + 1, pixelSize.Height));
PixelSnapHelpers.PixelAlign(r.Bottom, pixelSize.Height));
} else {
AddRectangle(r.Left, r.Top + 1, r.Right, r.Bottom + 1);
AddRectangle(r.Left, r.Top, r.Right, r.Bottom);
}
}

Просмотреть файл

@ -484,7 +484,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
{
if (xPos > textLine.WidthIncludingTrailingWhitespace) {
if (allowVirtualSpace && textLine == TextLines[TextLines.Count - 1]) {
int virtualX = (int)Math.Round((xPos - textLine.WidthIncludingTrailingWhitespace) / textView.WideSpaceWidth);
int virtualX = (int)Math.Round((xPos - textLine.WidthIncludingTrailingWhitespace) / textView.WideSpaceWidth, MidpointRounding.AwayFromZero);
return VisualLengthWithEndOfLineMarker + virtualX;
}
}

Просмотреть файл

@ -80,7 +80,8 @@ namespace ICSharpCode.AvalonEdit.Search
foreach (SearchResult result in currentResults.FindOverlappingSegments(viewStart, viewEnd - viewStart)) {
BackgroundGeometryBuilder geoBuilder = new BackgroundGeometryBuilder();
geoBuilder.AlignToMiddleOfPixels = true;
geoBuilder.AlignToWholePixels = true;
geoBuilder.BorderThickness = markerPen != null ? markerPen.Thickness : 0;
geoBuilder.CornerRadius = 3;
geoBuilder.AddSegment(textView, result);
Geometry geometry = geoBuilder.CreateGeometry();

Просмотреть файл

@ -203,7 +203,8 @@ namespace ICSharpCode.AvalonEdit.Snippets
ISegment s = element.Segment;
if (s != null) {
BackgroundGeometryBuilder geoBuilder = new BackgroundGeometryBuilder();
geoBuilder.AlignToMiddleOfPixels = true;
geoBuilder.AlignToWholePixels = true;
geoBuilder.BorderThickness = activeBorderPen != null ? activeBorderPen.Thickness : 0;
if (Layer == KnownLayer.Background) {
geoBuilder.AddSegment(textView, s);
drawingContext.DrawGeometry(backgroundBrush, null, geoBuilder.CreateGeometry());

Просмотреть файл

@ -56,7 +56,7 @@ namespace ICSharpCode.AvalonEdit.Utils
// 0.5 -> 0.5
// 0.9 -> 0.5
// 1 -> 1.5
return pixelSize * (Math.Round((value / pixelSize) + 0.5) - 0.5);
return pixelSize * (Math.Round((value / pixelSize) + 0.5, MidpointRounding.AwayFromZero) - 0.5);
}
/// <summary>
@ -93,7 +93,7 @@ namespace ICSharpCode.AvalonEdit.Utils
/// </summary>
public static double Round(double value, double pixelSize)
{
return pixelSize * Math.Round(value / pixelSize);
return pixelSize * Math.Round(value / pixelSize, MidpointRounding.AwayFromZero);
}
/// <summary>