Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Framework / System / Windows / Documents / CompositionAdorner.cs / 1 / CompositionAdorner.cs
//---------------------------------------------------------------------------- // // File: CompositionAdorner.cs // // Copyright (C) Microsoft Corporation. All rights reserved. // // Description: Composition adorner to render the composition display attribute. // //--------------------------------------------------------------------------- namespace System.Windows.Documents { using System.Collections; // ArrayList using System.Diagnostics; using System.Windows.Media; // Brush, Transform using System.Windows.Controls; // TextBox using System.Windows.Threading; // Dispatcher using MS.Win32; // TextServices using MS.Internal; // Invariant internal class CompositionAdorner : Adorner { //----------------------------------------------------- // // Constructors // //----------------------------------------------------- #region Constructors static CompositionAdorner() { // Provide a new default value for the composition adorner so that it is not hit-testable. IsEnabledProperty.OverrideMetadata(typeof(CompositionAdorner), new FrameworkPropertyMetadata(false)); } ////// Creates new instance of CompositionAdorner. /// /// /// TextView to which this CompositionAdorner is attached as adorner. /// internal CompositionAdorner(ITextView textView) : this(textView, new ArrayList()) { } ////// Creates new instance of CompositionAdorner. /// /// /// TextView to which this CompositionAdorner is attached as adorner. /// /// /// Attribute ranges /// internal CompositionAdorner(ITextView textView, ArrayList attributeRanges) : base(textView.RenderScope) { Debug.Assert(textView != null && textView.RenderScope != null); // TextView to which this CompositionAdorner is attached as adorner and it will // als be used for GetRectangleFromTextPosition/GetLineRange _textView = textView; // Create ArrayList for the composition attribute ranges and composition lines _attributeRanges = attributeRanges; } #endregion Constructors //------------------------------------------------------ // // Public Methods // //----------------------------------------------------- #region Public Methods ////// Add a transform so that the composition adorner gets positioned at the correct spot within the text being edited /// /// /// The transform applied to the object the adorner adorns /// ////// Transform to apply to the adorner /// public override GeneralTransform GetDesiredTransform(GeneralTransform transform) { TranslateTransform translation; GeneralTransformGroup group = new GeneralTransformGroup(); // Get the matrix transform out, skip all non affine transforms Transform t = transform.AffineTransform; if (t == null) { t = Transform.Identity; } // Translate the adorner to (0, 0) point translation = new TranslateTransform(-(t.Value.OffsetX), -(t.Value.OffsetY)); group.Children.Add(translation); if (transform != null) { group.Children.Add(transform); } return group; } #endregion Public Methods //------------------------------------------------------ // // Protected Methods // //------------------------------------------------------ #region Protected Methods ////// Render override to render the composition adorner here. /// protected override void OnRender(DrawingContext drawingContext) { // Get the matrix from AdornedElement to the visual parent to get the transformed // start/end point Visual parent2d = VisualTreeHelper.GetParent(this.AdornedElement) as Visual; if (parent2d == null) { return; } GeneralTransform transform = AdornedElement.TransformToAncestor(parent2d); if (transform == null) { return; } // Render the each of the composition string attribute from the attribute ranges. for (int i = 0; i < _attributeRanges.Count; i++) { DoubleCollection dashArray; // Get the composition attribute range from the attribute range lists AttributeRange attributeRange = (AttributeRange)_attributeRanges[i]; // Skip the rendering composition lines if the composition line doesn't exist. if (attributeRange.CompositionLines.Count == 0) { continue; } // Set the line bold and squiggle bool lineBold = attributeRange.TextServicesDisplayAttribute.IsBoldLine ? true : false; bool squiggle = false; // Set the line height and cluse gap value that base on the ratio of text height double height = attributeRange.Height; double lineHeight = height * (lineBold ? BoldLineHeightRatio : NormalLineHeightRatio); double clauseGap = height * ClauseGapRatio; // Create Pen for drawing the composition lines with the specified line color Pen pen = new Pen(new SolidColorBrush(attributeRange.TextServicesDisplayAttribute.LineColor), lineHeight); // Set the pen style that based on IME's composition line style switch (attributeRange.TextServicesDisplayAttribute.LineStyle) { case UnsafeNativeMethods.TF_DA_LINESTYLE.TF_LS_DOT: // Add the dot length and specify the start/end line cap as the round dashArray = new DoubleCollection(); dashArray.Add(DotLength); dashArray.Add(DotLength); pen.DashStyle = new DashStyle(dashArray, 0); pen.DashCap = System.Windows.Media.PenLineCap.Round; pen.StartLineCap = System.Windows.Media.PenLineCap.Round; pen.EndLineCap = System.Windows.Media.PenLineCap.Round; // Update the line height for the dot line. Dot line will be more thickness than // other line to show it clearly. lineHeight = height * (lineBold ? BoldDotLineHeightRatio : NormalDotLineHeightRatio); break; case UnsafeNativeMethods.TF_DA_LINESTYLE.TF_LS_DASH: double dashLength = height * (lineBold ? BoldDashRatio : NormalDashRatio); double dashGapLength = height * (lineBold ? BoldDashGapRatio : NormalDashGapRatio); // Add the dash and dash gap legth dashArray = new DoubleCollection(); dashArray.Add(dashLength); dashArray.Add(dashGapLength); pen.DashStyle = new DashStyle(dashArray, 0); pen.DashCap = System.Windows.Media.PenLineCap.Round; pen.StartLineCap = System.Windows.Media.PenLineCap.Round; pen.EndLineCap = System.Windows.Media.PenLineCap.Round; break; case UnsafeNativeMethods.TF_DA_LINESTYLE.TF_LS_SOLID: pen.StartLineCap = System.Windows.Media.PenLineCap.Round; pen.EndLineCap = System.Windows.Media.PenLineCap.Round; break; case UnsafeNativeMethods.TF_DA_LINESTYLE.TF_LS_SQUIGGLE: squiggle = true; break; } double halfLineHeight = lineHeight / 2; // Draw the each of the composition line for (int j = 0; j < attributeRange.CompositionLines.Count; j++) { CompositionLine compositionLine = (CompositionLine)attributeRange.CompositionLines[j]; // Get the start/end point for composition adorner. // Currently Text doesn't aware of the spaceroom for the drawing of the composition // adorner(like as normal/bold dot/line/squggle), so we should draw the composition adorners // to the closest area of the bottom text. Point startPoint = new Point(compositionLine.Start.X + clauseGap, compositionLine.Start.Y - lineHeight / 4); Point endPoint = new Point(compositionLine.End.X - clauseGap, compositionLine.End.Y - lineHeight / 4); // Apply matrix to start/end point // transform.TryTransform(startPoint, out startPoint); transform.TryTransform(endPoint, out endPoint); if (squiggle) { // Draw the squiggle line with using of the PathFigure and DrawGemetry. // We may revisit this logic to render the smooth squiggle line. Point pathPoint = new Point(startPoint.X, startPoint.Y + halfLineHeight); double squiggleGap = halfLineHeight; PathFigure pathFigure = new PathFigure(); pathFigure.StartPoint = pathPoint; int indexPoint = 0; while (indexPoint < ((endPoint.X - startPoint.X) / (squiggleGap))) { if (indexPoint % 4 == 0 || indexPoint % 4 == 3) { pathPoint = new Point(pathPoint.X + squiggleGap, pathPoint.Y + halfLineHeight); pathFigure.Segments.Add(new LineSegment(pathPoint, true)); } else if (indexPoint % 4 == 1 || indexPoint % 4 == 2) { pathPoint = new Point(pathPoint.X + squiggleGap, pathPoint.Y - halfLineHeight); pathFigure.Segments.Add(new LineSegment(pathPoint, true)); } indexPoint++; } PathGeometry pathGeometry = new PathGeometry(); pathGeometry.Figures.Add(pathFigure); // Draw the composition line with the squiggle drawingContext.DrawGeometry(null, pen, pathGeometry); } else { drawingContext.DrawLine(pen, startPoint, endPoint); } } } } #endregion Protected Events //----------------------------------------------------- // // Internal Methods // //------------------------------------------------------ #region Internal Methods ////// Add the composition attribute range that will be rendered. /// Used in TextServicesDisplayAttributePropertyRanges (for composition display attribute) /// internal void AddAttributeRange(ITextPointer start, ITextPointer end, TextServicesDisplayAttribute textServiceDisplayAttribute) { // Set the range start/end point's logical direction ITextPointer rangeStart = start.CreatePointer(LogicalDirection.Forward); ITextPointer rangeEnd = end.CreatePointer(LogicalDirection.Backward); // Add the composition attribute range _attributeRanges.Add(new AttributeRange(_textView, rangeStart, rangeEnd, textServiceDisplayAttribute)); } ////// Invalidates the CompositionAdorner render. /// Used in TextServicesDisplayAttributePropertyRanges (for composition display attribute) /// internal void InvalidateAdorner() { for (int i = 0; i < _attributeRanges.Count; i++) { // Get the composition attribute range from the attribute range lists AttributeRange attributeRange = (AttributeRange)_attributeRanges[i]; // Add the composition lines for rendering the composition lines attributeRange.AddCompositionLines(); } // Invalidate the CompositionAdorner to update the rendering. AdornerLayer adornerLayer = VisualTreeHelper.GetParent(this) as AdornerLayer; if (adornerLayer != null) { adornerLayer.Update(AdornedElement); adornerLayer.InvalidateArrange(); } } ////// Add CompositionAdorner to the scoping AdornerLayer. /// internal void Initialize(ITextView textView) { Debug.Assert(_adornerLayer == null, "Attempt to overwrite existing AdornerLayer!"); _adornerLayer = AdornerLayer.GetAdornerLayer(textView.RenderScope); if (_adornerLayer != null) { // Add the CompositionAdorner to the scoping of AdornerLayer _adornerLayer.Add(this); } } ////// Remove this CompositionAdorner from its AdornerLayer. /// internal void Uninitialize() { if (_adornerLayer != null) { // Remove CompositionAdorner form the socping of AdornerLayer _adornerLayer.Remove(this); _adornerLayer = null; } } #endregion Internal methods //----------------------------------------------------- // // Private Fields // //----------------------------------------------------- #region Private Fields // AdornerLayer holding this CompositionAdorner visual private AdornerLayer _adornerLayer; // TextView to which this CompositionAdorner is attached as adorner private ITextView _textView; // ArrayList for the composition attribute ranges private readonly ArrayList _attributeRanges; // Composition line's dot length private const double DotLength = 1.2; // Ratio of the composition line private const double NormalLineHeightRatio = 0.06; // Ratio of the bold composition line private const double BoldLineHeightRatio = 0.08; // Ratio of the composition line of dot private const double NormalDotLineHeightRatio = 0.08; // Ratio of the bold composition line of dot private const double BoldDotLineHeightRatio = 0.10; // Ratio of the composition line's dash private const double NormalDashRatio = 0.27; // Ratio of the bold composition line's dash private const double BoldDashRatio = 0.39; // Ratio of the composition line's clause gap private const double ClauseGapRatio = 0.09; // Ratio of the composition line's dash gap private const double NormalDashGapRatio = 0.04; // Ratio of the bold composition line's dash gap private const double BoldDashGapRatio = 0.06; #endregion Private Fields //----------------------------------------------------- // // Private Class // //------------------------------------------------------ private class AttributeRange { //----------------------------------------------------- // // Constructors // //------------------------------------------------------ #region Constructors internal AttributeRange(ITextView textView, ITextPointer start, ITextPointer end, TextServicesDisplayAttribute textServicesDisplayAttribute) { _textView = textView; _startOffset = start.Offset; _endOffset = end.Offset; _textServicesDisplayAttribute = textServicesDisplayAttribute; _compositionLines = new ArrayList(1); } #endregion Constructors //------------------------------------------------------ // // Internal Methods // //----------------------------------------------------- #region Internal Methods // Add the composition lines for rendering the composition lines. internal void AddCompositionLines() { // Erase any current lines. _compositionLines.Clear(); ITextPointer start = _textView.TextContainer.Start.CreatePointer(_startOffset, LogicalDirection.Forward); ITextPointer end = _textView.TextContainer.Start.CreatePointer(_endOffset, LogicalDirection.Backward); while (start.CompareTo(end) < 0 && start.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.Text) { start.MoveToNextContextPosition(LogicalDirection.Forward); } Invariant.Assert(start.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text); if (end.HasValidLayout) { // Get the rectangle for start/end position _startRect = _textView.GetRectangleFromTextPosition(start); _endRect = _textView.GetRectangleFromTextPosition(end); // Check whether the composition line is single or multiple lines if (_startRect.Top != _endRect.Top) { // Add the composition lines to be rendered for the composition string AddMultipleCompositionLines(start, end); } else { // Set the start/end pointer to draw the line Point startPoint = new Point(_startRect.Left, _startRect.Bottom); Point endPoint = new Point(_endRect.Right, _endRect.Bottom); // Add the composition line to be rendered _compositionLines.Add(new CompositionLine(startPoint, endPoint)); } } } #endregion Internal Methods //------------------------------------------------------ // // Internal Properties // //----------------------------------------------------- #region Internal Properties ////// Height of the composition attribute range. /// internal double Height { get { return _startRect.Bottom - _startRect.Top; } } ////// CompositionLines of the composition attribute range. /// internal ArrayList CompositionLines { get { return _compositionLines; } } ////// Composition attribute information. /// internal TextServicesDisplayAttribute TextServicesDisplayAttribute { get { return _textServicesDisplayAttribute; } } #endregion Internal Properties //----------------------------------------------------- // // Private Methods // //----------------------------------------------------- #region Private Methods private void AddMultipleCompositionLines(ITextPointer start, ITextPointer end) { // Initalize the start/end line pointer ITextPointer startLinePointer = start; ITextPointer endLinePointer = startLinePointer; // Get all composition lines that includes the start/end pointer while (endLinePointer.CompareTo(end) < 0) { TextSegment textSegment = _textView.GetLineRange(endLinePointer); if (textSegment.IsNull) { // endLinePointer is not within the TextView's definition of a line. // Skip ahead to text on the next iteration. startLinePointer = endLinePointer; } else { Debug.Assert(start.CompareTo(startLinePointer) <= 0, "The start pointer is positioned after the composition start line pointer!"); if (startLinePointer.CompareTo(textSegment.Start) < 0) { // Update the start line pointer startLinePointer = textSegment.Start; } if (endLinePointer.CompareTo(textSegment.End) < 0) { if (end.CompareTo(textSegment.End) < 0) { // Update the end line pointer endLinePointer = end.CreatePointer(); } else { // Update the end line pointer endLinePointer = textSegment.End.CreatePointer(LogicalDirection.Backward); } } else { Debug.Assert(endLinePointer.CompareTo(textSegment.End) == 0, "The end line pointer is positioned after the composition text range end pointer!"); } // Get the rectangle for start/end position Rect startRect = _textView.GetRectangleFromTextPosition(startLinePointer); Rect endRect = _textView.GetRectangleFromTextPosition(endLinePointer); // Set the start/end pointer to draw the line Point startPoint = new Point(startRect.Left, startRect.Bottom); Point endPoint = new Point(endRect.Right, endRect.Bottom); // Add the composition line to be rendered _compositionLines.Add(new CompositionLine(startPoint, endPoint)); startLinePointer = textSegment.End.CreatePointer(LogicalDirection.Forward); } // Move the start pointer to the next text line. startLinePointer must be a pointer to start // text. while ((startLinePointer.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.None) && (startLinePointer.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.Text)) { startLinePointer.MoveToNextContextPosition(LogicalDirection.Forward); } endLinePointer = startLinePointer; } } #endregion Private methods //------------------------------------------------------ // // Private Fields // //----------------------------------------------------- #region Private Fields // TextView to which this CompositionAdorner is attached as adorner private ITextView _textView; // Start rect of the composition attribute range private Rect _startRect; // End rect of the composition attribute range private Rect _endRect; // Start position offset of the composition attribute range private readonly int _startOffset; // End position offset of the composition attribute range private readonly int _endOffset; // Composition display attribute that is specified from IME private readonly TextServicesDisplayAttribute _textServicesDisplayAttribute; // ArrayList for the composition lines private readonly ArrayList _compositionLines; #endregion Private Fields } private class CompositionLine { //------------------------------------------------------ // // Constructors // //------------------------------------------------------ #region Constructors internal CompositionLine(Point start, Point end) { _start = start; _end = end; } #endregion Constructors //----------------------------------------------------- // // Internal Properties // //------------------------------------------------------ #region Internal Properties ////// Start point of the composition line draw /// internal Point Start { get { return _start; } } ////// End point of the composition line draw /// internal Point End { get { return _end; } } #endregion Internal Properties //----------------------------------------------------- // // Private Fields // //----------------------------------------------------- #region Private Fields // Start point of the composition line draw private Point _start; // End point of the composition line draw private Point _end; #endregion Private Fields } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------------- // // File: CompositionAdorner.cs // // Copyright (C) Microsoft Corporation. All rights reserved. // // Description: Composition adorner to render the composition display attribute. // //--------------------------------------------------------------------------- namespace System.Windows.Documents { using System.Collections; // ArrayList using System.Diagnostics; using System.Windows.Media; // Brush, Transform using System.Windows.Controls; // TextBox using System.Windows.Threading; // Dispatcher using MS.Win32; // TextServices using MS.Internal; // Invariant internal class CompositionAdorner : Adorner { //----------------------------------------------------- // // Constructors // //----------------------------------------------------- #region Constructors static CompositionAdorner() { // Provide a new default value for the composition adorner so that it is not hit-testable. IsEnabledProperty.OverrideMetadata(typeof(CompositionAdorner), new FrameworkPropertyMetadata(false)); } ////// Creates new instance of CompositionAdorner. /// /// /// TextView to which this CompositionAdorner is attached as adorner. /// internal CompositionAdorner(ITextView textView) : this(textView, new ArrayList()) { } ////// Creates new instance of CompositionAdorner. /// /// /// TextView to which this CompositionAdorner is attached as adorner. /// /// /// Attribute ranges /// internal CompositionAdorner(ITextView textView, ArrayList attributeRanges) : base(textView.RenderScope) { Debug.Assert(textView != null && textView.RenderScope != null); // TextView to which this CompositionAdorner is attached as adorner and it will // als be used for GetRectangleFromTextPosition/GetLineRange _textView = textView; // Create ArrayList for the composition attribute ranges and composition lines _attributeRanges = attributeRanges; } #endregion Constructors //------------------------------------------------------ // // Public Methods // //----------------------------------------------------- #region Public Methods ////// Add a transform so that the composition adorner gets positioned at the correct spot within the text being edited /// /// /// The transform applied to the object the adorner adorns /// ////// Transform to apply to the adorner /// public override GeneralTransform GetDesiredTransform(GeneralTransform transform) { TranslateTransform translation; GeneralTransformGroup group = new GeneralTransformGroup(); // Get the matrix transform out, skip all non affine transforms Transform t = transform.AffineTransform; if (t == null) { t = Transform.Identity; } // Translate the adorner to (0, 0) point translation = new TranslateTransform(-(t.Value.OffsetX), -(t.Value.OffsetY)); group.Children.Add(translation); if (transform != null) { group.Children.Add(transform); } return group; } #endregion Public Methods //------------------------------------------------------ // // Protected Methods // //------------------------------------------------------ #region Protected Methods ////// Render override to render the composition adorner here. /// protected override void OnRender(DrawingContext drawingContext) { // Get the matrix from AdornedElement to the visual parent to get the transformed // start/end point Visual parent2d = VisualTreeHelper.GetParent(this.AdornedElement) as Visual; if (parent2d == null) { return; } GeneralTransform transform = AdornedElement.TransformToAncestor(parent2d); if (transform == null) { return; } // Render the each of the composition string attribute from the attribute ranges. for (int i = 0; i < _attributeRanges.Count; i++) { DoubleCollection dashArray; // Get the composition attribute range from the attribute range lists AttributeRange attributeRange = (AttributeRange)_attributeRanges[i]; // Skip the rendering composition lines if the composition line doesn't exist. if (attributeRange.CompositionLines.Count == 0) { continue; } // Set the line bold and squiggle bool lineBold = attributeRange.TextServicesDisplayAttribute.IsBoldLine ? true : false; bool squiggle = false; // Set the line height and cluse gap value that base on the ratio of text height double height = attributeRange.Height; double lineHeight = height * (lineBold ? BoldLineHeightRatio : NormalLineHeightRatio); double clauseGap = height * ClauseGapRatio; // Create Pen for drawing the composition lines with the specified line color Pen pen = new Pen(new SolidColorBrush(attributeRange.TextServicesDisplayAttribute.LineColor), lineHeight); // Set the pen style that based on IME's composition line style switch (attributeRange.TextServicesDisplayAttribute.LineStyle) { case UnsafeNativeMethods.TF_DA_LINESTYLE.TF_LS_DOT: // Add the dot length and specify the start/end line cap as the round dashArray = new DoubleCollection(); dashArray.Add(DotLength); dashArray.Add(DotLength); pen.DashStyle = new DashStyle(dashArray, 0); pen.DashCap = System.Windows.Media.PenLineCap.Round; pen.StartLineCap = System.Windows.Media.PenLineCap.Round; pen.EndLineCap = System.Windows.Media.PenLineCap.Round; // Update the line height for the dot line. Dot line will be more thickness than // other line to show it clearly. lineHeight = height * (lineBold ? BoldDotLineHeightRatio : NormalDotLineHeightRatio); break; case UnsafeNativeMethods.TF_DA_LINESTYLE.TF_LS_DASH: double dashLength = height * (lineBold ? BoldDashRatio : NormalDashRatio); double dashGapLength = height * (lineBold ? BoldDashGapRatio : NormalDashGapRatio); // Add the dash and dash gap legth dashArray = new DoubleCollection(); dashArray.Add(dashLength); dashArray.Add(dashGapLength); pen.DashStyle = new DashStyle(dashArray, 0); pen.DashCap = System.Windows.Media.PenLineCap.Round; pen.StartLineCap = System.Windows.Media.PenLineCap.Round; pen.EndLineCap = System.Windows.Media.PenLineCap.Round; break; case UnsafeNativeMethods.TF_DA_LINESTYLE.TF_LS_SOLID: pen.StartLineCap = System.Windows.Media.PenLineCap.Round; pen.EndLineCap = System.Windows.Media.PenLineCap.Round; break; case UnsafeNativeMethods.TF_DA_LINESTYLE.TF_LS_SQUIGGLE: squiggle = true; break; } double halfLineHeight = lineHeight / 2; // Draw the each of the composition line for (int j = 0; j < attributeRange.CompositionLines.Count; j++) { CompositionLine compositionLine = (CompositionLine)attributeRange.CompositionLines[j]; // Get the start/end point for composition adorner. // Currently Text doesn't aware of the spaceroom for the drawing of the composition // adorner(like as normal/bold dot/line/squggle), so we should draw the composition adorners // to the closest area of the bottom text. Point startPoint = new Point(compositionLine.Start.X + clauseGap, compositionLine.Start.Y - lineHeight / 4); Point endPoint = new Point(compositionLine.End.X - clauseGap, compositionLine.End.Y - lineHeight / 4); // Apply matrix to start/end point // transform.TryTransform(startPoint, out startPoint); transform.TryTransform(endPoint, out endPoint); if (squiggle) { // Draw the squiggle line with using of the PathFigure and DrawGemetry. // We may revisit this logic to render the smooth squiggle line. Point pathPoint = new Point(startPoint.X, startPoint.Y + halfLineHeight); double squiggleGap = halfLineHeight; PathFigure pathFigure = new PathFigure(); pathFigure.StartPoint = pathPoint; int indexPoint = 0; while (indexPoint < ((endPoint.X - startPoint.X) / (squiggleGap))) { if (indexPoint % 4 == 0 || indexPoint % 4 == 3) { pathPoint = new Point(pathPoint.X + squiggleGap, pathPoint.Y + halfLineHeight); pathFigure.Segments.Add(new LineSegment(pathPoint, true)); } else if (indexPoint % 4 == 1 || indexPoint % 4 == 2) { pathPoint = new Point(pathPoint.X + squiggleGap, pathPoint.Y - halfLineHeight); pathFigure.Segments.Add(new LineSegment(pathPoint, true)); } indexPoint++; } PathGeometry pathGeometry = new PathGeometry(); pathGeometry.Figures.Add(pathFigure); // Draw the composition line with the squiggle drawingContext.DrawGeometry(null, pen, pathGeometry); } else { drawingContext.DrawLine(pen, startPoint, endPoint); } } } } #endregion Protected Events //----------------------------------------------------- // // Internal Methods // //------------------------------------------------------ #region Internal Methods ////// Add the composition attribute range that will be rendered. /// Used in TextServicesDisplayAttributePropertyRanges (for composition display attribute) /// internal void AddAttributeRange(ITextPointer start, ITextPointer end, TextServicesDisplayAttribute textServiceDisplayAttribute) { // Set the range start/end point's logical direction ITextPointer rangeStart = start.CreatePointer(LogicalDirection.Forward); ITextPointer rangeEnd = end.CreatePointer(LogicalDirection.Backward); // Add the composition attribute range _attributeRanges.Add(new AttributeRange(_textView, rangeStart, rangeEnd, textServiceDisplayAttribute)); } ////// Invalidates the CompositionAdorner render. /// Used in TextServicesDisplayAttributePropertyRanges (for composition display attribute) /// internal void InvalidateAdorner() { for (int i = 0; i < _attributeRanges.Count; i++) { // Get the composition attribute range from the attribute range lists AttributeRange attributeRange = (AttributeRange)_attributeRanges[i]; // Add the composition lines for rendering the composition lines attributeRange.AddCompositionLines(); } // Invalidate the CompositionAdorner to update the rendering. AdornerLayer adornerLayer = VisualTreeHelper.GetParent(this) as AdornerLayer; if (adornerLayer != null) { adornerLayer.Update(AdornedElement); adornerLayer.InvalidateArrange(); } } ////// Add CompositionAdorner to the scoping AdornerLayer. /// internal void Initialize(ITextView textView) { Debug.Assert(_adornerLayer == null, "Attempt to overwrite existing AdornerLayer!"); _adornerLayer = AdornerLayer.GetAdornerLayer(textView.RenderScope); if (_adornerLayer != null) { // Add the CompositionAdorner to the scoping of AdornerLayer _adornerLayer.Add(this); } } ////// Remove this CompositionAdorner from its AdornerLayer. /// internal void Uninitialize() { if (_adornerLayer != null) { // Remove CompositionAdorner form the socping of AdornerLayer _adornerLayer.Remove(this); _adornerLayer = null; } } #endregion Internal methods //----------------------------------------------------- // // Private Fields // //----------------------------------------------------- #region Private Fields // AdornerLayer holding this CompositionAdorner visual private AdornerLayer _adornerLayer; // TextView to which this CompositionAdorner is attached as adorner private ITextView _textView; // ArrayList for the composition attribute ranges private readonly ArrayList _attributeRanges; // Composition line's dot length private const double DotLength = 1.2; // Ratio of the composition line private const double NormalLineHeightRatio = 0.06; // Ratio of the bold composition line private const double BoldLineHeightRatio = 0.08; // Ratio of the composition line of dot private const double NormalDotLineHeightRatio = 0.08; // Ratio of the bold composition line of dot private const double BoldDotLineHeightRatio = 0.10; // Ratio of the composition line's dash private const double NormalDashRatio = 0.27; // Ratio of the bold composition line's dash private const double BoldDashRatio = 0.39; // Ratio of the composition line's clause gap private const double ClauseGapRatio = 0.09; // Ratio of the composition line's dash gap private const double NormalDashGapRatio = 0.04; // Ratio of the bold composition line's dash gap private const double BoldDashGapRatio = 0.06; #endregion Private Fields //----------------------------------------------------- // // Private Class // //------------------------------------------------------ private class AttributeRange { //----------------------------------------------------- // // Constructors // //------------------------------------------------------ #region Constructors internal AttributeRange(ITextView textView, ITextPointer start, ITextPointer end, TextServicesDisplayAttribute textServicesDisplayAttribute) { _textView = textView; _startOffset = start.Offset; _endOffset = end.Offset; _textServicesDisplayAttribute = textServicesDisplayAttribute; _compositionLines = new ArrayList(1); } #endregion Constructors //------------------------------------------------------ // // Internal Methods // //----------------------------------------------------- #region Internal Methods // Add the composition lines for rendering the composition lines. internal void AddCompositionLines() { // Erase any current lines. _compositionLines.Clear(); ITextPointer start = _textView.TextContainer.Start.CreatePointer(_startOffset, LogicalDirection.Forward); ITextPointer end = _textView.TextContainer.Start.CreatePointer(_endOffset, LogicalDirection.Backward); while (start.CompareTo(end) < 0 && start.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.Text) { start.MoveToNextContextPosition(LogicalDirection.Forward); } Invariant.Assert(start.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text); if (end.HasValidLayout) { // Get the rectangle for start/end position _startRect = _textView.GetRectangleFromTextPosition(start); _endRect = _textView.GetRectangleFromTextPosition(end); // Check whether the composition line is single or multiple lines if (_startRect.Top != _endRect.Top) { // Add the composition lines to be rendered for the composition string AddMultipleCompositionLines(start, end); } else { // Set the start/end pointer to draw the line Point startPoint = new Point(_startRect.Left, _startRect.Bottom); Point endPoint = new Point(_endRect.Right, _endRect.Bottom); // Add the composition line to be rendered _compositionLines.Add(new CompositionLine(startPoint, endPoint)); } } } #endregion Internal Methods //------------------------------------------------------ // // Internal Properties // //----------------------------------------------------- #region Internal Properties ////// Height of the composition attribute range. /// internal double Height { get { return _startRect.Bottom - _startRect.Top; } } ////// CompositionLines of the composition attribute range. /// internal ArrayList CompositionLines { get { return _compositionLines; } } ////// Composition attribute information. /// internal TextServicesDisplayAttribute TextServicesDisplayAttribute { get { return _textServicesDisplayAttribute; } } #endregion Internal Properties //----------------------------------------------------- // // Private Methods // //----------------------------------------------------- #region Private Methods private void AddMultipleCompositionLines(ITextPointer start, ITextPointer end) { // Initalize the start/end line pointer ITextPointer startLinePointer = start; ITextPointer endLinePointer = startLinePointer; // Get all composition lines that includes the start/end pointer while (endLinePointer.CompareTo(end) < 0) { TextSegment textSegment = _textView.GetLineRange(endLinePointer); if (textSegment.IsNull) { // endLinePointer is not within the TextView's definition of a line. // Skip ahead to text on the next iteration. startLinePointer = endLinePointer; } else { Debug.Assert(start.CompareTo(startLinePointer) <= 0, "The start pointer is positioned after the composition start line pointer!"); if (startLinePointer.CompareTo(textSegment.Start) < 0) { // Update the start line pointer startLinePointer = textSegment.Start; } if (endLinePointer.CompareTo(textSegment.End) < 0) { if (end.CompareTo(textSegment.End) < 0) { // Update the end line pointer endLinePointer = end.CreatePointer(); } else { // Update the end line pointer endLinePointer = textSegment.End.CreatePointer(LogicalDirection.Backward); } } else { Debug.Assert(endLinePointer.CompareTo(textSegment.End) == 0, "The end line pointer is positioned after the composition text range end pointer!"); } // Get the rectangle for start/end position Rect startRect = _textView.GetRectangleFromTextPosition(startLinePointer); Rect endRect = _textView.GetRectangleFromTextPosition(endLinePointer); // Set the start/end pointer to draw the line Point startPoint = new Point(startRect.Left, startRect.Bottom); Point endPoint = new Point(endRect.Right, endRect.Bottom); // Add the composition line to be rendered _compositionLines.Add(new CompositionLine(startPoint, endPoint)); startLinePointer = textSegment.End.CreatePointer(LogicalDirection.Forward); } // Move the start pointer to the next text line. startLinePointer must be a pointer to start // text. while ((startLinePointer.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.None) && (startLinePointer.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.Text)) { startLinePointer.MoveToNextContextPosition(LogicalDirection.Forward); } endLinePointer = startLinePointer; } } #endregion Private methods //------------------------------------------------------ // // Private Fields // //----------------------------------------------------- #region Private Fields // TextView to which this CompositionAdorner is attached as adorner private ITextView _textView; // Start rect of the composition attribute range private Rect _startRect; // End rect of the composition attribute range private Rect _endRect; // Start position offset of the composition attribute range private readonly int _startOffset; // End position offset of the composition attribute range private readonly int _endOffset; // Composition display attribute that is specified from IME private readonly TextServicesDisplayAttribute _textServicesDisplayAttribute; // ArrayList for the composition lines private readonly ArrayList _compositionLines; #endregion Private Fields } private class CompositionLine { //------------------------------------------------------ // // Constructors // //------------------------------------------------------ #region Constructors internal CompositionLine(Point start, Point end) { _start = start; _end = end; } #endregion Constructors //----------------------------------------------------- // // Internal Properties // //------------------------------------------------------ #region Internal Properties ////// Start point of the composition line draw /// internal Point Start { get { return _start; } } ////// End point of the composition line draw /// internal Point End { get { return _end; } } #endregion Internal Properties //----------------------------------------------------- // // Private Fields // //----------------------------------------------------- #region Private Fields // Start point of the composition line draw private Point _start; // End point of the composition line draw private Point _end; #endregion Private Fields } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- Int16AnimationBase.cs
- ChildTable.cs
- ReadOnlyState.cs
- MemberDescriptor.cs
- SettingsPropertyCollection.cs
- SchemaImporterExtensionElementCollection.cs
- TrackingMemoryStreamFactory.cs
- ClonableStack.cs
- Domain.cs
- DataRow.cs
- ScopedMessagePartSpecification.cs
- SqlDataSourceQuery.cs
- RemotingConfiguration.cs
- LambdaCompiler.Expressions.cs
- ContextQuery.cs
- XmlNavigatorFilter.cs
- UnaryNode.cs
- CodeSnippetCompileUnit.cs
- GlyphInfoList.cs
- NoPersistProperty.cs
- SystemParameters.cs
- XmlSchemaDocumentation.cs
- Rijndael.cs
- ErrorHandlerFaultInfo.cs
- WebServiceEndpoint.cs
- ImageMapEventArgs.cs
- CustomCategoryAttribute.cs
- BulletedList.cs
- InProcStateClientManager.cs
- ToolStripItemRenderEventArgs.cs
- IisTraceListener.cs
- dbenumerator.cs
- SynchronizationContext.cs
- PageAsyncTaskManager.cs
- MailMessageEventArgs.cs
- SecurityTokenException.cs
- RelatedCurrencyManager.cs
- GPRECTF.cs
- OdbcConnectionFactory.cs
- DeflateStream.cs
- SingleObjectCollection.cs
- Environment.cs
- BamlBinaryWriter.cs
- TypeName.cs
- TypeUsageBuilder.cs
- ConfigurationPermission.cs
- SqlCommandSet.cs
- FontStyleConverter.cs
- PropertyReference.cs
- AnchoredBlock.cs
- SymbolTable.cs
- WebPartConnectionsConfigureVerb.cs
- ObjectFullSpanRewriter.cs
- TransportSecurityHelpers.cs
- VisualCollection.cs
- FlowDocumentFormatter.cs
- ValidatingReaderNodeData.cs
- DynamicResourceExtension.cs
- LabelLiteral.cs
- DictionaryTraceRecord.cs
- ResXResourceReader.cs
- GlobalEventManager.cs
- IgnoreFileBuildProvider.cs
- ValidationSummary.cs
- DefaultPrintController.cs
- TemplateAction.cs
- StandardBindingElementCollection.cs
- BufferedReadStream.cs
- MethodExecutor.cs
- CodeGotoStatement.cs
- Size3D.cs
- ConnectionPoint.cs
- XmlReflectionImporter.cs
- XXXOnTypeBuilderInstantiation.cs
- RenameRuleObjectDialog.Designer.cs
- DeploymentSection.cs
- COAUTHIDENTITY.cs
- Inline.cs
- SelectionPatternIdentifiers.cs
- SingleSelectRootGridEntry.cs
- CanExpandCollapseAllConverter.cs
- InputProviderSite.cs
- AdvancedBindingPropertyDescriptor.cs
- XmlSchemas.cs
- DataGridViewCheckBoxCell.cs
- ToolStripPanelCell.cs
- CompilationLock.cs
- ScrollChrome.cs
- FontNamesConverter.cs
- ChangeNode.cs
- Partitioner.cs
- ContentIterators.cs
- DLinqTableProvider.cs
- ConditionBrowserDialog.cs
- Binding.cs
- ObjectConverter.cs
- TextElement.cs
- LinearGradientBrush.cs
- DataGridViewImageCell.cs
- ReflectPropertyDescriptor.cs