Skip to content

Commit 6f76dd9

Browse files
committed
Consider border thickness when rounding to pixel boundaries (#38).
1 parent 532cab0 commit 6f76dd9

11 files changed

Lines changed: 63 additions & 24 deletions

File tree

ICSharpCode.AvalonEdit.Sample/ICSharpCode.AvalonEdit.Sample.csproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
<TreatWarningsAsErrors>False</TreatWarningsAsErrors>
1717
<IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
1818
<WarningLevel>4</WarningLevel>
19-
<PlatformTarget>AnyCPU</PlatformTarget>
19+
<PlatformTarget>x86</PlatformTarget>
2020
<BaseAddress>4194304</BaseAddress>
2121
<RegisterForComInterop>False</RegisterForComInterop>
2222
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
@@ -40,8 +40,8 @@
4040
<Optimize>False</Optimize>
4141
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
4242
<BaseIntermediateOutputPath>obj\</BaseIntermediateOutputPath>
43-
<DefineDebug>True</DefineDebug>
44-
<DefineTrace>True</DefineTrace>
43+
<DefineDebug>True</DefineDebug>
44+
<DefineTrace>True</DefineTrace>
4545
</PropertyGroup>
4646
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
4747
<OutputPath>bin\Release\</OutputPath>
@@ -50,7 +50,7 @@
5050
<Optimize>True</Optimize>
5151
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
5252
<BaseIntermediateOutputPath>obj\</BaseIntermediateOutputPath>
53-
<DefineTrace>True</DefineTrace>
53+
<DefineTrace>True</DefineTrace>
5454
</PropertyGroup>
5555
<ItemGroup>
5656
<ProjectReference Include="..\..\NRefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj" Condition="$(DefineConstants.Contains('NREFACTORY'))">

ICSharpCode.AvalonEdit.Sample/Window1.xaml.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ public Window1()
6060
#endif
6161
propertyGridComboBox.SelectedIndex = 2;
6262

63+
//textEditor.TextArea.SelectionBorder = null;
64+
6365
//textEditor.SyntaxHighlighting = HighlightingManager.Instance.GetDefinition("C#");
6466
//textEditor.SyntaxHighlighting = customHighlighting;
6567
// initial highlighting now set by XAML

ICSharpCode.AvalonEdit/Editing/SelectionLayer.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
using System.Windows.Media;
2222

2323
using ICSharpCode.AvalonEdit.Rendering;
24+
using ICSharpCode.AvalonEdit.Utils;
2425

2526
namespace ICSharpCode.AvalonEdit.Editing
2627
{
@@ -52,16 +53,19 @@ protected override void OnRender(DrawingContext drawingContext)
5253
{
5354
base.OnRender(drawingContext);
5455

56+
var selectionBorder = textArea.SelectionBorder;
57+
5558
BackgroundGeometryBuilder geoBuilder = new BackgroundGeometryBuilder();
56-
geoBuilder.AlignToMiddleOfPixels = true;
59+
geoBuilder.AlignToWholePixels = true;
60+
geoBuilder.BorderThickness = selectionBorder != null ? selectionBorder.Thickness : 0;
5761
geoBuilder.ExtendToFullWidthAtLineEnd = textArea.Selection.EnableVirtualSpace;
5862
geoBuilder.CornerRadius = textArea.SelectionCornerRadius;
5963
foreach (var segment in textArea.Selection.Segments) {
6064
geoBuilder.AddSegment(textView, segment);
6165
}
6266
Geometry geometry = geoBuilder.CreateGeometry();
6367
if (geometry != null) {
64-
drawingContext.DrawGeometry(textArea.SelectionBrush, textArea.SelectionBorder, geometry);
68+
drawingContext.DrawGeometry(textArea.SelectionBrush, selectionBorder, geometry);
6569
}
6670
}
6771
}

ICSharpCode.AvalonEdit/Editing/TextArea.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,7 @@ public Brush SelectionBrush {
470470
DependencyProperty.Register("SelectionForeground", typeof(Brush), typeof(TextArea));
471471

472472
/// <summary>
473-
/// Gets/Sets the foreground brush used selected text.
473+
/// Gets/Sets the foreground brush used for selected text.
474474
/// </summary>
475475
public Brush SelectionForeground {
476476
get { return (Brush)GetValue(SelectionForegroundProperty); }
@@ -484,7 +484,7 @@ public Brush SelectionForeground {
484484
DependencyProperty.Register("SelectionBorder", typeof(Pen), typeof(TextArea));
485485

486486
/// <summary>
487-
/// Gets/Sets the background brush used for the selection.
487+
/// Gets/Sets the pen used for the border of the selection.
488488
/// </summary>
489489
public Pen SelectionBorder {
490490
get { return (Pen)GetValue(SelectionBorderProperty); }

ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
<AssemblyOriginatorKeyFile>..\..\NRefactory\ICSharpCode.NRefactory.snk</AssemblyOriginatorKeyFile>
4343
</PropertyGroup>
4444
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
45+
<DefineConstants>DEBUG;$(DefineConstants)</DefineConstants>
4546
<OutputPath>bin\Debug\</OutputPath>
4647
<DocumentationFile>bin\Debug\ICSharpCode.AvalonEdit.xml</DocumentationFile>
4748
<DebugSymbols>true</DebugSymbols>

ICSharpCode.AvalonEdit/Properties/AssemblyInfo.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
[assembly: AssemblyCompany("ic#code")]
5555
[assembly: AssemblyProduct("SharpDevelop")]
5656
[assembly: AssemblyCopyright("2000-2014 AlphaSierraPapa for the SharpDevelop Team")]
57-
[assembly: AssemblyVersion("5.0.1")]
57+
[assembly: AssemblyVersion("5.0.3")]
5858
[assembly: NeutralResourcesLanguage("en-US")]
5959

6060
[assembly: XmlnsPrefix("http://icsharpcode.net/sharpdevelop/avalonedit", "avalonedit")]

ICSharpCode.AvalonEdit/Rendering/BackgroundGeometryBuilder.cs

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
using System;
2020
using System.Collections.Generic;
21+
using System.Diagnostics;
2122
using System.Linq;
2223
using System.Windows;
2324
using System.Windows.Controls.Primitives;
@@ -46,14 +47,41 @@ public double CornerRadius {
4647
}
4748

4849
/// <summary>
49-
/// Gets/Sets whether to align the geometry to whole pixels.
50+
/// Gets/Sets whether to align to whole pixels.
51+
///
52+
/// If BorderThickness is set to 0, the geometry is aligned to whole pixels.
53+
/// If BorderThickness is set to a non-zero value, the outer edge of the border is aligned
54+
/// to whole pixels.
55+
///
56+
/// The default value is <c>false</c>.
5057
/// </summary>
5158
public bool AlignToWholePixels { get; set; }
5259

60+
/// <summary>
61+
/// Gets/sets the border thickness.
62+
///
63+
/// This property only has an effect if <c>AlignToWholePixels</c> is enabled.
64+
/// When using the resulting geometry to paint a border, set this property to the border thickness.
65+
/// Otherwise, leave the property set to the default value <c>0</c>.
66+
/// </summary>
67+
public double BorderThickness { get; set; }
68+
69+
bool alignToMiddleOfPixels;
70+
5371
/// <summary>
5472
/// Gets/Sets whether to align the geometry to the middle of pixels.
5573
/// </summary>
56-
public bool AlignToMiddleOfPixels { get; set; }
74+
[Obsolete("Use the AlignToWholePixels and BorderThickness properties instead. "
75+
+ "Setting AlignToWholePixels=true and setting the BorderThickness to the pixel size "
76+
+ "is equivalent to aligning the geometry to the middle of pixels.")]
77+
public bool AlignToMiddleOfPixels {
78+
get {
79+
return alignToMiddleOfPixels;
80+
}
81+
set {
82+
alignToMiddleOfPixels = value;
83+
}
84+
}
5785

5886
/// <summary>
5987
/// Gets/Sets whether to extend the rectangles to full width at line end.
@@ -96,17 +124,19 @@ public void AddRectangle(TextView textView, Rect rectangle)
96124
void AddRectangle(Size pixelSize, Rect r)
97125
{
98126
if (AlignToWholePixels) {
99-
AddRectangle(PixelSnapHelpers.Round(r.Left, pixelSize.Width),
100-
PixelSnapHelpers.Round(r.Top + 1, pixelSize.Height),
101-
PixelSnapHelpers.Round(r.Right, pixelSize.Width),
102-
PixelSnapHelpers.Round(r.Bottom + 1, pixelSize.Height));
103-
} else if (AlignToMiddleOfPixels) {
127+
double halfBorder = 0.5 * BorderThickness;
128+
AddRectangle(PixelSnapHelpers.Round(r.Left - halfBorder, pixelSize.Width) + halfBorder,
129+
PixelSnapHelpers.Round(r.Top - halfBorder, pixelSize.Height) + halfBorder,
130+
PixelSnapHelpers.Round(r.Right + halfBorder, pixelSize.Width) - halfBorder,
131+
PixelSnapHelpers.Round(r.Bottom + halfBorder, pixelSize.Height) - halfBorder);
132+
//Debug.WriteLine(r.ToString() + " -> " + new Rect(lastLeft, lastTop, lastRight-lastLeft, lastBottom-lastTop).ToString());
133+
} else if (alignToMiddleOfPixels) {
104134
AddRectangle(PixelSnapHelpers.PixelAlign(r.Left, pixelSize.Width),
105-
PixelSnapHelpers.PixelAlign(r.Top + 1, pixelSize.Height),
135+
PixelSnapHelpers.PixelAlign(r.Top, pixelSize.Height),
106136
PixelSnapHelpers.PixelAlign(r.Right, pixelSize.Width),
107-
PixelSnapHelpers.PixelAlign(r.Bottom + 1, pixelSize.Height));
137+
PixelSnapHelpers.PixelAlign(r.Bottom, pixelSize.Height));
108138
} else {
109-
AddRectangle(r.Left, r.Top + 1, r.Right, r.Bottom + 1);
139+
AddRectangle(r.Left, r.Top, r.Right, r.Bottom);
110140
}
111141
}
112142

ICSharpCode.AvalonEdit/Rendering/VisualLine.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,7 @@ public int GetVisualColumn(TextLine textLine, double xPos, bool allowVirtualSpac
484484
{
485485
if (xPos > textLine.WidthIncludingTrailingWhitespace) {
486486
if (allowVirtualSpace && textLine == TextLines[TextLines.Count - 1]) {
487-
int virtualX = (int)Math.Round((xPos - textLine.WidthIncludingTrailingWhitespace) / textView.WideSpaceWidth);
487+
int virtualX = (int)Math.Round((xPos - textLine.WidthIncludingTrailingWhitespace) / textView.WideSpaceWidth, MidpointRounding.AwayFromZero);
488488
return VisualLengthWithEndOfLineMarker + virtualX;
489489
}
490490
}

ICSharpCode.AvalonEdit/Search/SearchResultBackgroundRenderer.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ public void Draw(TextView textView, DrawingContext drawingContext)
8080

8181
foreach (SearchResult result in currentResults.FindOverlappingSegments(viewStart, viewEnd - viewStart)) {
8282
BackgroundGeometryBuilder geoBuilder = new BackgroundGeometryBuilder();
83-
geoBuilder.AlignToMiddleOfPixels = true;
83+
geoBuilder.AlignToWholePixels = true;
84+
geoBuilder.BorderThickness = markerPen != null ? markerPen.Thickness : 0;
8485
geoBuilder.CornerRadius = 3;
8586
geoBuilder.AddSegment(textView, result);
8687
Geometry geometry = geoBuilder.CreateGeometry();

ICSharpCode.AvalonEdit/Snippets/SnippetReplaceableTextElement.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,8 @@ public void Draw(TextView textView, System.Windows.Media.DrawingContext drawingC
203203
ISegment s = element.Segment;
204204
if (s != null) {
205205
BackgroundGeometryBuilder geoBuilder = new BackgroundGeometryBuilder();
206-
geoBuilder.AlignToMiddleOfPixels = true;
206+
geoBuilder.AlignToWholePixels = true;
207+
geoBuilder.BorderThickness = activeBorderPen != null ? activeBorderPen.Thickness : 0;
207208
if (Layer == KnownLayer.Background) {
208209
geoBuilder.AddSegment(textView, s);
209210
drawingContext.DrawGeometry(backgroundBrush, null, geoBuilder.CreateGeometry());

0 commit comments

Comments
 (0)