private void DrawString(string text, SimpleFont font, DXMediaBrush brush, double pointX, double pointY, DXMediaBrush areaBrush) { SharpDX.DirectWrite.TextFormat textFormat = font.ToDirectWriteTextFormat(); SharpDX.DirectWrite.TextLayout textLayout = new SharpDX.DirectWrite.TextLayout(NinjaTrader.Core.Globals.DirectWriteFactory, text, textFormat, ChartPanel.X + ChartPanel.W, textFormat.FontSize); float newW = textLayout.Metrics.Width; float newH = textLayout.Metrics.Height; SharpDX.Vector2 TextPlotPoint = new System.Windows.Point(pointX - newW, pointY - textLayout.Metrics.Height / 2 - 1).ToVector2(); SharpDX.RectangleF PLBoundRect = new SharpDX.RectangleF((float)pointX - newW - 4, (float)pointY - textLayout.Metrics.Height / 2 - 1, newW + 6, newH + 2); SharpDX.Direct2D1.RoundedRectangle PLRoundedRect = new SharpDX.Direct2D1.RoundedRectangle(); PLRoundedRect.RadiusX = newW / 4; PLRoundedRect.RadiusY = newH / 4; PLRoundedRect.Rect = PLBoundRect; RenderTarget.FillRoundedRectangle(PLRoundedRect, areaBrush.DxBrush); RenderTarget.DrawTextLayout(TextPlotPoint, textLayout, brush.DxBrush, SharpDX.Direct2D1.DrawTextOptions.NoSnap); textLayout.Dispose(); textLayout = null; textFormat.Dispose(); textFormat = null; }
private void DrawString(string text, SimpleFont font, string brushName, double pointX, double pointY, string areaBrushName) { SharpDX.DirectWrite.TextFormat textFormat = font.ToDirectWriteTextFormat(); SharpDX.Vector2 TextPlotPoint = new System.Windows.Point(pointX, pointY).ToVector2(); SharpDX.DirectWrite.TextLayout textLayout = new SharpDX.DirectWrite.TextLayout(NinjaTrader.Core.Globals.DirectWriteFactory, text, textFormat, ChartPanel.X + ChartPanel.W, textFormat.FontSize); float newW = textLayout.Metrics.Width; float newH = textLayout.Metrics.Height; SharpDX.RectangleF PLBoundRect = new SharpDX.RectangleF((float)pointX + 2, (float)pointY, newW + 5, newH + 2); RenderTarget.FillRectangle(PLBoundRect, dxmBrushes[areaBrushName].DxBrush); RenderTarget.DrawTextLayout(TextPlotPoint, textLayout, dxmBrushes[brushName].DxBrush, SharpDX.Direct2D1.DrawTextOptions.NoSnap); textLayout.Dispose(); textFormat.Dispose(); }
public override void OnRender(ChartControl chartControl, ChartScale chartScale) { if (firstTime && DrawingState == DrawingState.Normal) { firstTime = false; Cbi.License.Log("Path"); } RenderTarget.AntialiasMode = SharpDX.Direct2D1.AntialiasMode.PerPrimitive; Stroke outlineStroke = OutlineStroke; outlineStroke.RenderTarget = RenderTarget; ChartPanel chartPanel = chartControl.ChartPanels[PanelIndex]; double strokePixAdjust = outlineStroke.Width % 2 == 0 ? 0.5d : 0d; Vector pixelAdjustVec = new Vector(strokePixAdjust, strokePixAdjust); SharpDX.Direct2D1.PathGeometry polyGeo = CreatePathGeometry(chartControl, chartPanel, chartScale, strokePixAdjust); SharpDX.Direct2D1.Brush tmpBrush = IsInHitTest ? chartControl.SelectionBrush : outlineStroke.BrushDX; RenderTarget.DrawGeometry(polyGeo, tmpBrush, outlineStroke.Width, outlineStroke.StrokeStyle); polyGeo.Dispose(); if (PathBegin == PathToolCapMode.Arrow || PathEnd == PathToolCapMode.Arrow) { Point[] points = GetPathAnchorPoints(chartControl, chartScale); if (points.Length > 1) { if (arrowPathGeometry == null) { arrowPathGeometry = new SharpDX.Direct2D1.PathGeometry(Core.Globals.D2DFactory); SharpDX.Direct2D1.GeometrySink geometrySink = arrowPathGeometry.Open(); float arrowWidth = 6f; SharpDX.Vector2 top = new SharpDX.Vector2(0, outlineStroke.Width * 0.5f); geometrySink.BeginFigure(top, SharpDX.Direct2D1.FigureBegin.Filled); geometrySink.AddLine(new SharpDX.Vector2(arrowWidth, -arrowWidth)); geometrySink.AddLine(new SharpDX.Vector2(-arrowWidth, -arrowWidth)); geometrySink.AddLine(top); // cap off figure geometrySink.EndFigure(SharpDX.Direct2D1.FigureEnd.Closed); geometrySink.Close(); } if (PathBegin == PathToolCapMode.Arrow) { Vector lineVector = points[0] - points[1]; lineVector.Normalize(); Point pointAdjusted = points[0] + pixelAdjustVec; SharpDX.Vector2 pointVec = pointAdjusted.ToVector2(); float vectorAngle = -(float)Math.Atan2(lineVector.X, lineVector.Y); Vector adjustVector = lineVector * 5; SharpDX.Vector2 arrowPointVec = new SharpDX.Vector2((float)(pointVec.X + adjustVector.X), (float)(pointVec.Y + adjustVector.Y)); SharpDX.Matrix3x2 transformMatrix2 = SharpDX.Matrix3x2.Rotation(vectorAngle, SharpDX.Vector2.Zero) * SharpDX.Matrix3x2.Scaling((float)Math.Max(1.0f, outlineStroke.Width * .45) + 0.25f) * SharpDX.Matrix3x2.Translation(arrowPointVec); RenderTarget.Transform = transformMatrix2; RenderTarget.FillGeometry(arrowPathGeometry, tmpBrush); RenderTarget.Transform = SharpDX.Matrix3x2.Identity; } if (PathEnd == PathToolCapMode.Arrow) { Vector lineVector = points[points.Length - 1] - points[points.Length - 2]; lineVector.Normalize(); Point pointAdjusted = points[points.Length - 1] + pixelAdjustVec; SharpDX.Vector2 pointVec = pointAdjusted.ToVector2(); float vectorAngle = -(float)Math.Atan2(lineVector.X, lineVector.Y); Vector adjustVector = lineVector * 5; SharpDX.Vector2 arrowPointVec = new SharpDX.Vector2((float)(pointVec.X + adjustVector.X), (float)(pointVec.Y + adjustVector.Y)); SharpDX.Matrix3x2 transformMatrix2 = SharpDX.Matrix3x2.Rotation(vectorAngle, SharpDX.Vector2.Zero) * SharpDX.Matrix3x2.Scaling((float)Math.Max(1.0f, outlineStroke.Width * .45) + 0.25f) * SharpDX.Matrix3x2.Translation(arrowPointVec); RenderTarget.Transform = transformMatrix2; RenderTarget.FillGeometry(arrowPathGeometry, tmpBrush); RenderTarget.Transform = SharpDX.Matrix3x2.Identity; } } } if (ShowCount) { SimpleFont wpfFont = chartControl.Properties.LabelFont ?? new SimpleFont(); SharpDX.DirectWrite.TextFormat textFormat = wpfFont.ToDirectWriteTextFormat(); textFormat.TextAlignment = SharpDX.DirectWrite.TextAlignment.Leading; textFormat.WordWrapping = SharpDX.DirectWrite.WordWrapping.NoWrap; for (int i = 1; i < ChartAnchors.Count; i++) { Point p = ChartAnchors[i - 1].GetPoint(chartControl, chartPanel, chartScale); Point p1 = ChartAnchors[i].GetPoint(chartControl, chartPanel, chartScale); if (i + 1 < ChartAnchors.Count) { Point p2 = ChartAnchors[i + 1].GetPoint(chartControl, chartPanel, chartScale); Vector v1 = p - p1; v1.Normalize(); Vector v2 = p2 - p1; v2.Normalize(); Vector vector = v1 + v2; vector.Normalize(); SharpDX.DirectWrite.TextLayout textLayout = new SharpDX.DirectWrite.TextLayout(Core.Globals.DirectWriteFactory, i.ToString(), textFormat, 250, textFormat.FontSize); Point textPoint = p1 - vector * textFormat.FontSize; textPoint.X -= textLayout.Metrics.Width / 2f; textPoint.Y -= textLayout.Metrics.Height / 2f; RenderTarget.DrawTextLayout((textPoint + pixelAdjustVec).ToVector2(), textLayout, outlineStroke.BrushDX, SharpDX.Direct2D1.DrawTextOptions.NoSnap); textLayout.Dispose(); } else { SharpDX.DirectWrite.TextLayout textLayout = new SharpDX.DirectWrite.TextLayout(Core.Globals.DirectWriteFactory, i.ToString(), textFormat, 250, textFormat.FontSize); Vector vector = (p - p1); vector.Normalize(); Point textPoint = p1 - vector * textFormat.FontSize; textPoint.X -= textLayout.Metrics.Width / 2f; textPoint.Y -= textLayout.Metrics.Height / 2f; RenderTarget.DrawTextLayout((textPoint + pixelAdjustVec).ToVector2(), textLayout, outlineStroke.BrushDX, SharpDX.Direct2D1.DrawTextOptions.NoSnap); textLayout.Dispose(); } } textFormat.Dispose(); } }
private void DrawPriceText(ChartAnchor anchor, Point point, double price, ChartControl chartControl, ChartPanel chartPanel, ChartScale chartScale) { if (TextAlignment == TextLocation.Off) { return; } string priceString; ChartBars chartBars = GetAttachedToChartBars(); // bars can be null while chart is initializing if (chartBars == null) { return; } priceString = GetPriceString(price, chartBars); Stroke color; textleftPoint = RiskAnchor.GetPoint(chartControl, chartPanel, chartScale).X; textRightPoint = EntryAnchor.GetPoint(chartControl, chartPanel, chartScale).X; if (anchor == RewardAnchor) { color = TargetLineStroke; } else if (anchor == RiskAnchor) { color = StopLineStroke; } else if (anchor == EntryAnchor) { color = EntryLineStroke; } else { color = AnchorLineStroke; } SimpleFont wpfFont = chartControl.Properties.LabelFont ?? new SimpleFont(); SharpDX.DirectWrite.TextFormat textFormat = wpfFont.ToDirectWriteTextFormat(); textFormat.TextAlignment = SharpDX.DirectWrite.TextAlignment.Leading; textFormat.WordWrapping = SharpDX.DirectWrite.WordWrapping.NoWrap; SharpDX.DirectWrite.TextLayout textLayout = new SharpDX.DirectWrite.TextLayout(Core.Globals.DirectWriteFactory, priceString, textFormat, chartPanel.H, textFormat.FontSize); if (RiskAnchor.Time <= EntryAnchor.Time) { if (!IsExtendedLinesLeft && !IsExtendedLinesRight) { switch (TextAlignment) { case TextLocation.InsideLeft: point.X = textleftPoint; break; case TextLocation.InsideRight: point.X = textRightPoint - textLayout.Metrics.Width; break; case TextLocation.ExtremeLeft: point.X = textleftPoint; break; case TextLocation.ExtremeRight: point.X = textRightPoint - textLayout.Metrics.Width; break; } } else if (IsExtendedLinesLeft && !IsExtendedLinesRight) { switch (TextAlignment) { case TextLocation.InsideLeft: point.X = textleftPoint; break; case TextLocation.InsideRight: point.X = textRightPoint - textLayout.Metrics.Width; break; case TextLocation.ExtremeLeft: point.X = chartPanel.X; break; case TextLocation.ExtremeRight: point.X = textRightPoint - textLayout.Metrics.Width; break; } } else if (!IsExtendedLinesLeft && IsExtendedLinesRight) { switch (TextAlignment) { case TextLocation.InsideLeft: point.X = textleftPoint; break; case TextLocation.InsideRight: point.X = textRightPoint - textLayout.Metrics.Width; break; case TextLocation.ExtremeLeft: point.X = textleftPoint; break; case TextLocation.ExtremeRight: point.X = chartPanel.W - textLayout.Metrics.Width; break; } } else if (IsExtendedLinesLeft && IsExtendedLinesRight) { switch (TextAlignment) { case TextLocation.InsideLeft: point.X = textleftPoint; break; case TextLocation.InsideRight: point.X = textRightPoint - textLayout.Metrics.Width; break; case TextLocation.ExtremeRight: point.X = chartPanel.W - textLayout.Metrics.Width; break; case TextLocation.ExtremeLeft: point.X = chartPanel.X; break; } } } else if (RiskAnchor.Time >= EntryAnchor.Time) { if (!IsExtendedLinesLeft && !IsExtendedLinesRight) { switch (TextAlignment) { case TextLocation.InsideLeft: point.X = textRightPoint; break; case TextLocation.InsideRight: point.X = textleftPoint - textLayout.Metrics.Width; break; case TextLocation.ExtremeLeft: point.X = textRightPoint; break; case TextLocation.ExtremeRight: point.X = textleftPoint - textLayout.Metrics.Width; break; } } else if (IsExtendedLinesLeft && !IsExtendedLinesRight) { switch (TextAlignment) { case TextLocation.InsideLeft: point.X = textRightPoint; break; case TextLocation.InsideRight: point.X = textleftPoint - textLayout.Metrics.Width; break; case TextLocation.ExtremeLeft: point.X = chartPanel.X; break; case TextLocation.ExtremeRight: point.X = textleftPoint - textLayout.Metrics.Width; break; } } else if (!IsExtendedLinesLeft && IsExtendedLinesRight) { switch (TextAlignment) { case TextLocation.InsideLeft: point.X = textRightPoint; break; case TextLocation.InsideRight: point.X = textleftPoint - textLayout.Metrics.Width; break; case TextLocation.ExtremeLeft: point.X = textRightPoint; break; case TextLocation.ExtremeRight: point.X = chartPanel.W - textLayout.Metrics.Width; break; } } else if (IsExtendedLinesLeft && IsExtendedLinesRight) { switch (TextAlignment) { case TextLocation.InsideLeft: point.X = textRightPoint; break; case TextLocation.InsideRight: point.X = textleftPoint - textLayout.Metrics.Width; break; case TextLocation.ExtremeRight: point.X = chartPanel.W - textLayout.Metrics.Width; break; case TextLocation.ExtremeLeft: point.X = chartPanel.X; break; } } } RenderTarget.DrawTextLayout(new SharpDX.Vector2((float)point.X, (float)point.Y), textLayout, color.BrushDX, SharpDX.Direct2D1.DrawTextOptions.NoSnap); }
public override void OnRender(ChartControl chartControl, ChartScale chartScale) { RenderTarget.AntialiasMode = SharpDX.Direct2D1.AntialiasMode.PerPrimitive; ChartPanel panel = chartControl.ChartPanels[PanelIndex]; Point anchorPoint = Anchor.GetPoint(chartControl, panel, chartScale); Point lastEndPoint = new Point(0, 0); SharpDX.Direct2D1.Brush lastBrush = null; foreach (GannAngle gannAngle in GannAngles.Where(ga => ga.IsVisible && ga.Stroke != null).OrderBy(ga => (ga.RatioX / ga.RatioY))) { gannAngle.Stroke.RenderTarget = RenderTarget; double dx = gannAngle.RatioX * chartControl.Properties.BarDistance; double dVal = gannAngle.RatioY * PointsPerBar; //NT7, just multiple directly this is price not pixels //chartScale.GetPixelsForDistance(gannAngle.RatioY * PointsPerBar); Vector gannDataVector = GetGannStepDataVector(dx, dVal); Point extendedEndPoint = CalculateExtendedDataPoint(panel, chartScale, Convert.ToInt32(anchorPoint.X), Anchor.Price, gannDataVector); // align to full pixel to avoid unneeded aliasing double strokePixAdj = ((double)(gannAngle.Stroke.Width % 2)).ApproxCompare(0) == 0 ? 0.5d : 0d; Vector pixelAdjustVec = new Vector(0, strokePixAdj); SharpDX.Direct2D1.Brush tmpBrush = IsInHitTest ? chartControl.SelectionBrush : gannAngle.Stroke.BrushDX; RenderTarget.DrawLine((anchorPoint + pixelAdjustVec).ToVector2(), (extendedEndPoint + pixelAdjustVec).ToVector2(), tmpBrush, gannAngle.Stroke.Width, gannAngle.Stroke.StrokeStyle); if (lastBrush != null) { float oldOpacity = lastBrush.Opacity; lastBrush.Opacity = PriceLevelOpacity / 100f; // create geometry SharpDX.Direct2D1.PathGeometry lineGeometry = new SharpDX.Direct2D1.PathGeometry(Core.Globals.D2DFactory); SharpDX.Direct2D1.GeometrySink sink = lineGeometry.Open(); sink.BeginFigure(lastEndPoint.ToVector2(), SharpDX.Direct2D1.FigureBegin.Filled); // Does the fill color need to fill a corner? Check and add a point if (Math.Abs(lastEndPoint.Y - extendedEndPoint.Y) > 0.1 && Math.Abs(lastEndPoint.X - extendedEndPoint.X) > 0.1) { double boundaryX; double boundaryY; if (lastEndPoint.Y <= ChartPanel.Y || lastEndPoint.Y >= ChartPanel.Y + ChartPanel.H) { if (FanDirection == GannFanDirection.UpLeft || FanDirection == GannFanDirection.UpRight) { boundaryY = extendedEndPoint.Y; boundaryX = lastEndPoint.X; } else { boundaryY = lastEndPoint.Y; boundaryX = extendedEndPoint.X; } } else { if (FanDirection == GannFanDirection.UpLeft || FanDirection == GannFanDirection.UpRight) { boundaryY = lastEndPoint.Y; boundaryX = extendedEndPoint.X; } else { boundaryY = extendedEndPoint.Y; boundaryX = lastEndPoint.X; } } sink.AddLine(new SharpDX.Vector2((float)boundaryX, (float)boundaryY)); } sink.AddLine(extendedEndPoint.ToVector2()); sink.AddLine((anchorPoint + pixelAdjustVec).ToVector2()); sink.AddLine((lastEndPoint).ToVector2()); sink.EndFigure(SharpDX.Direct2D1.FigureEnd.Closed); sink.Close(); RenderTarget.FillGeometry(lineGeometry, lastBrush); lineGeometry.Dispose(); lastBrush.Opacity = oldOpacity; } lastEndPoint = extendedEndPoint + pixelAdjustVec; lastBrush = tmpBrush; } if (!IsTextDisplayed || IsInHitTest) { return; } foreach (GannAngle gannAngle in GannAngles.Where(ga => ga.IsVisible && ga.Stroke != null).OrderBy(ga => (ga.RatioX / ga.RatioY))) { gannAngle.Stroke.RenderTarget = RenderTarget; double dx = gannAngle.RatioX * chartControl.Properties.BarDistance; double dVal = gannAngle.RatioY * PointsPerBar; //NT7, just multiple directly this is price not pixels //chartScale.GetPixelsForDistance(gannAngle.RatioY * PointsPerBar); Vector gannDataVector = GetGannStepDataVector(dx, dVal); Point extendedEndPoint = CalculateExtendedDataPoint(panel, chartScale, Convert.ToInt32(anchorPoint.X), Anchor.Price, gannDataVector); if (!IsTextDisplayed || IsInHitTest) { continue; } SimpleFont wpfFont = chartControl.Properties.LabelFont ?? new SimpleFont(); SharpDX.DirectWrite.TextFormat textFormat = wpfFont.ToDirectWriteTextFormat(); textFormat.TextAlignment = SharpDX.DirectWrite.TextAlignment.Leading; textFormat.WordWrapping = SharpDX.DirectWrite.WordWrapping.NoWrap; SharpDX.DirectWrite.TextLayout textLayout = new SharpDX.DirectWrite.TextLayout(Core.Globals.DirectWriteFactory, gannAngle.Name, textFormat, 100, textFormat.FontSize); // once text is laid out, update used width to calcuated space required float fontHeight = textLayout.Metrics.Height; Point textEndPoint = new Point(extendedEndPoint.X, extendedEndPoint.Y); if (textEndPoint.X > panel.X + panel.W - textLayout.Metrics.Width) { textEndPoint.X = panel.X + panel.W - textLayout.Metrics.Width; textEndPoint.Y += textLayout.Metrics.Width; } if (gannDataVector.Y > 0) { if (textEndPoint.Y < panel.Y + (fontHeight * 0.5)) { textEndPoint.Y = panel.Y + (fontHeight * 0.5); } } else { if (textEndPoint.Y > panel.Y + panel.H - (fontHeight * 1.5)) { textEndPoint.Y = panel.Y + panel.H - (fontHeight * 1.5); } } float?marginResource = Application.Current.FindResource("FontModalTitleMargin") as float?; float margin = 2f + (marginResource.HasValue ? marginResource.Value : 3f); // Allow for changes in X position based on whether text is aligned to left or right edge of screen float marginX = FanDirection == GannFanDirection.DownLeft || FanDirection == GannFanDirection.UpLeft ? margin : -2 * margin; SharpDX.Vector2 endVec = new SharpDX.Vector2((float)textEndPoint.X, (float)textEndPoint.Y); SharpDX.Matrix3x2 transformMatrix = SharpDX.Matrix3x2.Translation(endVec); RenderTarget.Transform = transformMatrix; RenderTarget.DrawTextLayout(new SharpDX.Vector2(marginX + margin, margin), textLayout, gannAngle.Stroke.BrushDX, SharpDX.Direct2D1.DrawTextOptions.NoSnap); RenderTarget.Transform = SharpDX.Matrix3x2.Identity; textFormat.Dispose(); textLayout.Dispose(); } }
private void UpdateTextLayout(ChartControl chartControl, ChartPanel chartPanel, ChartScale chartScale) { if (isTextCreated && textLayout != null && !textLayout.IsDisposed) { return; } if (textFormat != null && !textFormat.IsDisposed) { textFormat.Dispose(); } if (textLayout != null && !textLayout.IsDisposed) { textLayout.Dispose(); } ChartBars chartBars = GetAttachedToChartBars(); // bars can be null while chart is initializing if (chartBars == null) { return; } double yDiffPrice = AttachedTo.Instrument.MasterInstrument.RoundToTickSize(EndAnchor.Price - StartAnchor.Price); double yDiffTicks = yDiffPrice / AttachedTo.Instrument.MasterInstrument.TickSize; switch (YValueDisplayUnit) { case ValueUnit.Price: yValueString = chartBars.Bars.Instrument.MasterInstrument.FormatPrice(yDiffPrice); break; case ValueUnit.Currency: yValueString = AttachedTo.Instrument.MasterInstrument.InstrumentType == InstrumentType.Forex ? Core.Globals.FormatCurrency((int)Math.Abs(yDiffTicks) * Account.All[0].ForexLotSize * (AttachedTo.Instrument.MasterInstrument.TickSize * AttachedTo.Instrument.MasterInstrument.PointValue)) : Core.Globals.FormatCurrency((int)Math.Abs(yDiffTicks) * (AttachedTo.Instrument.MasterInstrument.TickSize * AttachedTo.Instrument.MasterInstrument.PointValue)); break; case ValueUnit.Percent: yValueString = (yDiffPrice / AttachedTo.Instrument.MasterInstrument.RoundToTickSize(StartAnchor.Price)).ToString("P", Core.Globals.GeneralOptions.CurrentCulture); break; case ValueUnit.Ticks: yValueString = yDiffTicks.ToString("F0"); break; case ValueUnit.Pips: // show tenth pips (if available) double pips = Math.Abs(yDiffTicks / 10); char decimalChar = Char.Parse(Core.Globals.GeneralOptions.CurrentCulture.NumberFormat.NumberDecimalSeparator); yValueString = Int32.Parse(pips.ToString("F1").Split(decimalChar)[1]) > 0 ? pips.ToString("F1").Replace(decimalChar, '\'') : pips.ToString("F0"); break; } TimeSpan timeDiff = EndAnchor.Time - StartAnchor.Time; // trim off millis/ticks, match NT7 time formatting timeDiff = new TimeSpan(timeDiff.Days, timeDiff.Hours, timeDiff.Minutes, timeDiff.Seconds); bool isMultiDay = Math.Abs(timeDiff.TotalHours) >= 24; if (chartBars.Bars.BarsPeriod.BarsPeriodType == BarsPeriodType.Day) { int timeDiffDay = Math.Abs(timeDiff.Days); timeText = timeDiffDay > 1 ? Math.Abs(timeDiff.Days) + " " + Custom.Resource.Days : Math.Abs(timeDiff.Days) + " " + Custom.Resource.Day; } else { timeText = isMultiDay ? string.Format("{0}\n{1,25}", string.Format(Custom.Resource.NinjaScriptDrawingToolRulerDaysFormat, Math.Abs(timeDiff.Days)), timeDiff.Subtract(new TimeSpan(timeDiff.Days, 0, 0, 0)).Duration().ToString()) : timeDiff.Duration().ToString(); } Point startPoint = StartAnchor.GetPoint(chartControl, chartPanel, chartScale); Point endPoint = EndAnchor.GetPoint(chartControl, chartPanel, chartScale); int startIdx = chartBars.GetBarIdxByX(chartControl, (int)startPoint.X); int endIdx = chartBars.GetBarIdxByX(chartControl, (int)endPoint.X); int numBars = endIdx - startIdx; SimpleFont wpfFont = chartControl.Properties.LabelFont ?? new SimpleFont(); textFormat = wpfFont.ToDirectWriteTextFormat(); textFormat.TextAlignment = SharpDX.DirectWrite.TextAlignment.Leading; textFormat.WordWrapping = SharpDX.DirectWrite.WordWrapping.NoWrap; // format text to our text rectangle bounds (it will wrap to these constraints), nt7 format // NOTE: Environment.NewLine doesnt work right here string text = string.Format("{0}\n{1,-11}{2,-11}\n{3,-11}{4,-11}\n{5,-10}{6,-10}", AttachedTo.DisplayName, Custom.Resource.NinjaScriptDrawingToolRulerNumberBarsText, numBars, Custom.Resource.NinjaScriptDrawingToolRulerTimeText, timeText, Custom.Resource.NinjaScriptDrawingToolRulerYValueText, yValueString); // give big values for max width/height, we will trim to actual used textLayout = new SharpDX.DirectWrite.TextLayout(Core.Globals.DirectWriteFactory, text, textFormat, 600, 600); // use measured max width/height textLayout.MaxWidth = textLayout.Metrics.Width; textLayout.MaxHeight = textLayout.Metrics.Height; isTextCreated = true; }