Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / 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
- SmiConnection.cs
- KeyValueSerializer.cs
- DefaultWorkflowLoaderService.cs
- CookieParameter.cs
- ObjectIDGenerator.cs
- ListViewDeleteEventArgs.cs
- BypassElementCollection.cs
- MenuStrip.cs
- InputScopeNameConverter.cs
- WsdlBuildProvider.cs
- Delay.cs
- SelectedGridItemChangedEvent.cs
- Int16Storage.cs
- TextSyndicationContent.cs
- DrawingAttributes.cs
- future.cs
- GenericEnumConverter.cs
- ISAPIApplicationHost.cs
- SimpleBitVector32.cs
- ChildTable.cs
- XmlBindingWorker.cs
- WebBrowserSiteBase.cs
- MessageQueueKey.cs
- ResolveResponse.cs
- ProcessManager.cs
- GenericEnumerator.cs
- MailMessageEventArgs.cs
- SecurityState.cs
- FixedSOMTableCell.cs
- DetailsViewDeletedEventArgs.cs
- EventLogInformation.cs
- RegexCompilationInfo.cs
- PropertyMappingExceptionEventArgs.cs
- PipelineModuleStepContainer.cs
- login.cs
- RegexFCD.cs
- CategoryAttribute.cs
- IntegerValidator.cs
- CustomWebEventKey.cs
- Signature.cs
- wgx_render.cs
- ComplexType.cs
- FontFamilyConverter.cs
- Trace.cs
- FusionWrap.cs
- CachingParameterInspector.cs
- CardSpaceException.cs
- BinaryFormatter.cs
- RewritingValidator.cs
- XdrBuilder.cs
- DatagridviewDisplayedBandsData.cs
- DetailsViewModeEventArgs.cs
- DataObjectMethodAttribute.cs
- RootBrowserWindowAutomationPeer.cs
- ListItemCollection.cs
- RestHandlerFactory.cs
- ListControlStringCollectionEditor.cs
- SqlDataSourceStatusEventArgs.cs
- RenderTargetBitmap.cs
- ThicknessConverter.cs
- SafeProcessHandle.cs
- Authorization.cs
- ComponentSerializationService.cs
- WebScriptMetadataMessage.cs
- BindingWorker.cs
- ProfilePropertyNameValidator.cs
- ContextProperty.cs
- DateTimeFormat.cs
- Vector3DCollectionConverter.cs
- BitmapFrame.cs
- TraceContextEventArgs.cs
- RefExpr.cs
- MetadataPropertyvalue.cs
- SoundPlayer.cs
- FillErrorEventArgs.cs
- PrintDocument.cs
- DataGridViewCheckBoxCell.cs
- TextProviderWrapper.cs
- TemplateControlBuildProvider.cs
- storepermissionattribute.cs
- MultipleViewPatternIdentifiers.cs
- OverrideMode.cs
- InstanceNotReadyException.cs
- Font.cs
- ProvidersHelper.cs
- DataShape.cs
- UseManagedPresentationBindingElement.cs
- SystemInformation.cs
- Symbol.cs
- RNGCryptoServiceProvider.cs
- QueryCacheEntry.cs
- BaseDataListComponentEditor.cs
- CompiledRegexRunner.cs
- AnnotationHighlightLayer.cs
- SrgsOneOf.cs
- ObjectConverter.cs
- ServiceDeploymentInfo.cs
- UrlRoutingHandler.cs
- Site.cs
- XXXInfos.cs