/// <summary> /// Draws a previously laid-out text at a specified offset. /// </summary> public void Draw(float xOff, float yOff, RenderTextCallback renderCallback, DrawTextHint hint) { if (GetHLines(_totalLines) == null) { throw new Exception("Draw invoked on a non-laid-out text."); } if (GetHLines(_totalLines).Count == 0) { return; } bool styled = (_text is StyledText); bool is_LastWord = false; // Original brush and font System.Drawing.Brush brushOriginal = hint.Brush; Font fontOriginal = hint.Font; // We now have the starting line and the number // of total lines to layout the text in. Go for it int iword = 0; for (int i = _startLine; i < _startLine + _totalLines; i++) { PointList hLine = GetHLines(_totalLines)[i] as PointList; for (int j = 0; j < hLine.Count; j += 2) { PointF pt1 = hLine[j]; PointF pt2 = hLine[j + 1]; RectangleF rc = new RectangleF( _bounds.X + xOff + pt1.X, _bounds.Y + yOff + pt1.Y, pt2.X - pt1.X, pt2.Y - pt1.Y); bool newLine = false; int newword = FitTextInRect(iword, rc, ref newLine); if (newword > iword) { // Calculate the total width of the words // which are about to be rendered, but skip // the whitespaces at the front and the rear int ifront = iword; int irear = newword - 1; /*DON'T SKIP WHITESPACES ( next 2 lines ) * */ while (ifront < newword && _text.Words[ifront].IsWhitespace) { ifront++; } while (irear >= ifront && _text.Words[irear].IsWhitespace) { irear--; } int w; float total = 0; for (w = ifront; w <= irear; w++) { total += _text.Words[w].Width; } // Adjust the left side of the destination // rectangle according to the specified alignment switch (_options.Alignment) { case StringAlignment.Near: // Do nothing break; case StringAlignment.Center: rc.X = rc.X + (rc.Width - total) / 2; break; case StringAlignment.Far: rc.X = rc.Right - total; break; } // Render the words in the range [ifront, irear] for (w = ifront; w <= irear; w++) { Word word = _text.Words[w]; if (w == _text.Words.Count - 1) { is_LastWord = true; } else { is_LastWord = false; } if (!_fits && hint.AddEllipsis && styled) { if (i == _startLine + _totalLines - 1) { if (j == hLine.Count - 2) { if (w == irear) { // Append the last word with ellipsis StyledText.StyledWord sword = word as StyledText.StyledWord; StyledText.StyledWord newWord = null; int chars = sword.Value.Length; float width = sword.Width; do { newWord = new StyledText.StyledWord( sword.Value.Substring(0, chars) + "...", sword.Format, sword.Color); newWord.UpdateMeasures(hint.Graphics, hint.Font); chars--; }while (chars > 0 && newWord.Width > width); word = newWord; } } } } /*DON'T SKIP WHITESPACES ( next line ) * */ if (!word.IsLineBreak && !word.IsWhitespace) { if (styled) { // In case of styled text formatting, // apply fonts and colors StyledText.StyledWord sword = word as StyledText.StyledWord; hint.Font = sword.CreateFont(hint.Font); hint.Brush = sword.CreateBrush(hint.Brush); rc.Y += sword.YOffset; } // Add 10 to width and height becaus GDI+ stupid // and clips the text hint.IsLastLine = is_LastWord; hint.CurrentWord = word; renderCallback(word.Value, new RectangleF( rc.X, rc.Y, word.Width + 10, rc.Height + 10), hint); if (styled) { // Restore font and brush StyledText.StyledWord sword = word as StyledText.StyledWord; sword.DisposeFont(hint.Font); sword.DisposeBrush(hint.Brush); hint.Font = fontOriginal; hint.Brush = brushOriginal; rc.Y -= sword.YOffset; } } rc.X += _text.Words[w].Width; } iword = newword; } if (newLine) { break; } } } }
/// <summary> /// Callback internal routine called when text is being rended /// </summary> /// <param name="text">Rendered text</param> /// <param name="dest">Destination text area</param> /// <param name="hint">Hint object</param> internal void ___TextCallback(string text, RectangleF dest, DrawTextHint hint) { float fDX = 0, fDY = 0; sTextLine+=text; XmlNode new_tspan = null; if ( hint == null ) return; if ( hint.rect == RectangleF.Empty ) return; if ( hint.m_TextNode == null ) return; if ( m_lastY==0 ) { m_lastX = dest.X; m_lastY = dest.Y; } StyledText.StyledWord sword = null; if ( hint.CurrentWord is StyledText.StyledWord ) { sword = hint.CurrentWord as StyledText.StyledWord; } new_tspan = hint.m_TextNode.InsertAfter(m_InnerDoc.CreateNode(XmlNodeType.Element,"tspan", sNsDefault), hint.m_TextNode.LastChild); if ( new_tspan!=null) { new_tspan.InnerText = text; if ( IsTable) { if (m_lastY != dest.Y) { new_tspan.Attributes.Append(m_InnerDoc.CreateAttribute("x")); new_tspan.Attributes["x"].Value = Unit2PixStr(hint.rect.X + hint.rect.Width/2); new_tspan.Attributes.Append(m_InnerDoc.CreateAttribute("dy")); new_tspan.Attributes["dy"].Value = Unit2PixStr(dest.Y - m_lastY ); m_lastY = dest.Y; } } else { if (!IsTransparent) { fDX = (dest.Width - 10)/2; fDY = (dest.Height -10)/2; } if (sword != null) { if ( sword.YOffset!=0) { fDY-=sword.YOffset; Trace.WriteLine(String.Format("SWORD OFFSET: {0}",sword.YOffset)); } } if (!m_GlueLines ) { new_tspan.Attributes.Append(m_InnerDoc.CreateAttribute("x")); new_tspan.Attributes["x"].Value = Unit2PixStr(hint.rect.X + dest.X + fDX); new_tspan.Attributes.Append(m_InnerDoc.CreateAttribute("y")); new_tspan.Attributes["y"].Value = Unit2PixStr(hint.rect.Y + dest.Y + fDY ); } else { if (m_lastY != dest.Y) { new_tspan.Attributes.Append(m_InnerDoc.CreateAttribute("x")); new_tspan.Attributes["x"].Value = Unit2PixStr(hint.rect.X + hint.rect.Width/2); m_lastY = dest.Y; } new_tspan.Attributes.Append(m_InnerDoc.CreateAttribute("y")); new_tspan.Attributes["y"].Value = Unit2PixStr(hint.rect.Y + dest.Y + fDY ); } } if ( hint.CurrentWord is StyledText.StyledWord ) { new_tspan.Attributes.Append(m_InnerDoc.CreateAttribute("fill")); new_tspan.Attributes["fill"].Value = SvgManager.Color2Str(sword.Color); if (( sword.Format & Styles.Bold) >0 ) { new_tspan.Attributes.Append(m_InnerDoc.CreateAttribute("font-weight")); new_tspan.Attributes["font-weight"].Value = "bold"; } if (( sword.Format & Styles.Italic) >0 ) { new_tspan.Attributes.Append(m_InnerDoc.CreateAttribute("font-style")); new_tspan.Attributes["font-style"].Value = "italic"; } if (( sword.Format & Styles.Underline) >0 ) { new_tspan.Attributes.Append(m_InnerDoc.CreateAttribute("text-decoration")); new_tspan.Attributes["text-decoration"].Value = "underline"; } if (( sword.Format & Styles.Sup) >0 ) { new_tspan.Attributes.Append(m_InnerDoc.CreateAttribute("baseline-shift")); new_tspan.Attributes["baseline-shift"].Value = "super"; } if (( sword.Format & Styles.Sub) >0 ) { new_tspan.Attributes.Append(m_InnerDoc.CreateAttribute("baseline-shift")); new_tspan.Attributes["baseline-shift"].Value = "sub"; } } } ; }
/// <summary> /// Adds text to speciafied Flowchart.NET node /// </summary> /// <param name="ActiveNode">Node reference</param> /// <param name="Text2Render">String text to be added</param> /// <param name="Font2Render">Font to be used for text drawing</param> /// <param name="Rect2Render">Rectangle of the text area</param> /// <param name="Color2Render">Color for text rendering</param> /// <param name="TextFormat2Render">Text format for text renedering</param> /// <param name="IsStyled">If TRUE the text is styled</param> /// <returns>Returns recently added to SVG XML "text" node</returns> public XmlNode AddText( Node ActiveNode, string Text2Render, Font Font2Render, RectangleF Rect2Render, Color Color2Render, StringFormat TextFormat2Render , bool IsStyled , float angle) { Layout tl = null; LayoutOptions lo; DrawTextHint dhint = null; StyledText stext = null; PlainText text = null; System.Drawing.SolidBrush br = null; GraphicsPath path = null; PointF[] pF = null; string sPath = ""; double OffsetY = 0; double OffsetX = 0; int tlen = 0; try { if (( Text2Render == null ) || ( Text2Render=="")) return null; m_InnerNode = m_InnerRoot.InsertAfter(m_InnerDoc.CreateNode(XmlNodeType.Element,"text", sNsDefault), m_InnerRoot.LastChild); if ( m_InnerNode ==null ) return m_InnerNode; if ( TextFormat2Render.Alignment == StringAlignment.Near ) Rect2Render.Width+=15; path = new GraphicsPath(FillMode.Winding); IsTransparent = false; IsTable = false; if ( ActiveNode == null ) { sPath = Rect2Path(Rect2Render, ref path); } else if ( ActiveNode is Box ) { IsTransparent = ((Box) ActiveNode).Transparent; if ( ((Box) ActiveNode).Shape == null ) { sPath = Shape2Path((Box) ActiveNode, ref path , null); } else sPath = Complex2Path(Rect2Render, ( ((Box) ActiveNode).Shape.TextArea == null )? ((Box) ActiveNode).Shape.Outline : ((Box) ActiveNode).Shape.TextArea, ref path ); } else if ( ActiveNode is Table ) { sPath = Rect2Path(Rect2Render, ref path); IsTable = true; OffsetX = -Rect2Render.Width/2; } else { return null; } m_InnerNode.Attributes.Append(m_InnerDoc.CreateAttribute("x")); m_InnerNode.Attributes["x"].Value = String.Format("{0}px",Unit2Pix(Rect2Render.X+Rect2Render.Width/2)); m_InnerNode.Attributes.Append(m_InnerDoc.CreateAttribute("y")); m_InnerNode.Attributes["y"].Value = String.Format("{0}px",Unit2Pix(Rect2Render.Y + Rect2Render.Height/2)); m_InnerNode.Attributes.Append(m_InnerDoc.CreateAttribute("dx")); m_InnerNode.Attributes["dx"].Value = String.Format("{0}px",Unit2Pix(OffsetX)); m_InnerNode.Attributes.Append(m_InnerDoc.CreateAttribute("dy")); m_InnerNode.Attributes["dy"].Value = String.Format("{0}px",Unit2Pix(OffsetY)); m_InnerNode.Attributes.Append(m_InnerDoc.CreateAttribute("font-family")); m_InnerNode.Attributes["font-family"].Value = Font2Render.FontFamily.Name.ToString(); m_InnerNode.Attributes.Append(m_InnerDoc.CreateAttribute("font-size")); m_InnerNode.Attributes["font-size"].Value = Unit2Pix(Font2Render.Size, Font2Render.Unit).ToString(); m_InnerNode.Attributes.Append(m_InnerDoc.CreateAttribute("fill")); m_InnerNode.Attributes["fill"].Value = SvgManager.Color2Str(Color2Render); m_InnerNode.Attributes.Append(m_InnerDoc.CreateAttribute("style")); m_InnerNode.Attributes["style"].Value = SvgManager.Align2Str(TextFormat2Render.Alignment); IntPtr hWnd = GetActiveWindow(); if ( IsStyled ) { stext = new StyledText(); stext.Setup(Text2Render, System.Drawing.Graphics.FromHwnd(hWnd) ,Font2Render); tlen = stext.PlainText.Length; } else { text = new PlainText(); text.Setup(Text2Render, System.Drawing.Graphics.FromHwnd(hWnd) ,Font2Render); tlen = text.PlainText.Length; } path.Flatten(); pF = (PointF[])path.PathPoints.Clone(); path.Dispose(); tl = new Layout(); br = new System.Drawing.SolidBrush(Color2Render); lo = new LayoutOptions(); dhint = new DrawTextHint(System.Drawing.Graphics.FromHwnd(hWnd), Font2Render, br ,TextFormat2Render, false , m_InnerNode, Rect2Render ); m_lastY = 0; m_lastX = 0; sTextLine = ""; lo.Alignment = TextFormat2Render.Alignment; lo.LineAlignment = TextFormat2Render.LineAlignment; tl.LayoutInPolygon((IsStyled ? (Text) stext : (Text) text), docToLocal(pF, Rect2Render),lo); tl.Draw(0,0,new RenderTextCallback(___TextCallback),dhint); AddRotation(m_InnerNode, Rect2Render , angle ); } catch (Exception ex) { Trace.WriteLine(String.Format("{0} error {1}\n","SvgManager.AddText)",ex.Message)); } return m_InnerNode; }
/// <summary> /// Draws a previously laid-out text at a specified offset. /// </summary> public void Draw(float xOff, float yOff, RenderTextCallback renderCallback, DrawTextHint hint) { if (GetHLines(_totalLines) == null) throw new Exception("Draw invoked on a non-laid-out text."); if (GetHLines(_totalLines).Count == 0) return; bool styled = (_text is StyledText); bool is_LastWord = false; // Original brush and font System.Drawing.Brush brushOriginal = hint.Brush; Font fontOriginal = hint.Font; // We now have the starting line and the number // of total lines to layout the text in. Go for it int iword = 0; for (int i = _startLine; i < _startLine + _totalLines; i++) { PointList hLine = GetHLines(_totalLines)[i] as PointList; for (int j = 0; j < hLine.Count; j += 2) { PointF pt1 = hLine[j]; PointF pt2 = hLine[j + 1]; RectangleF rc = new RectangleF( _bounds.X + xOff + pt1.X, _bounds.Y + yOff + pt1.Y, pt2.X - pt1.X, pt2.Y - pt1.Y); bool newLine = false; int newword = FitTextInRect(iword, rc, ref newLine); if (newword > iword) { // Calculate the total width of the words // which are about to be rendered, but skip // the whitespaces at the front and the rear int ifront = iword; int irear = newword - 1; /*DON'T SKIP WHITESPACES ( next 2 lines ) * */ while (ifront < newword && _text.Words[ifront].IsWhitespace) ifront++; while (irear >= ifront && _text.Words[irear].IsWhitespace) irear--; int w; float total = 0; for (w = ifront; w <= irear; w++) total += _text.Words[w].Width; // Adjust the left side of the destination // rectangle according to the specified alignment switch (_options.Alignment) { case StringAlignment.Near: // Do nothing break; case StringAlignment.Center: rc.X = rc.X + (rc.Width - total) / 2; break; case StringAlignment.Far: rc.X = rc.Right - total; break; } // Render the words in the range [ifront, irear] for (w = ifront; w <= irear; w++) { Word word = _text.Words[w]; if ( w == _text.Words.Count -1 ) is_LastWord = true; else is_LastWord = false; if (!_fits && hint.AddEllipsis && styled) { if (i == _startLine + _totalLines - 1) { if (j == hLine.Count - 2) { if (w == irear) { // Append the last word with ellipsis StyledText.StyledWord sword = word as StyledText.StyledWord; StyledText.StyledWord newWord = null; int chars = sword.Value.Length; float width = sword.Width; do { newWord = new StyledText.StyledWord( sword.Value.Substring(0, chars) + "...", sword.Format, sword.Color); newWord.UpdateMeasures(hint.Graphics, hint.Font); chars--; } while (chars > 0 && newWord.Width > width); word = newWord; } } } } /*DON'T SKIP WHITESPACES ( next line ) * */ if (!word.IsLineBreak && !word.IsWhitespace) { if (styled) { // In case of styled text formatting, // apply fonts and colors StyledText.StyledWord sword = word as StyledText.StyledWord; hint.Font = sword.CreateFont(hint.Font); hint.Brush = sword.CreateBrush(hint.Brush); rc.Y += sword.YOffset; } // Add 10 to width and height becaus GDI+ stupid // and clips the text hint.IsLastLine = is_LastWord; hint.CurrentWord = word; renderCallback(word.Value, new RectangleF( rc.X, rc.Y, word.Width + 10 , rc.Height + 10), hint); if (styled) { // Restore font and brush StyledText.StyledWord sword = word as StyledText.StyledWord; sword.DisposeFont(hint.Font); sword.DisposeBrush(hint.Brush); hint.Font = fontOriginal; hint.Brush = brushOriginal; rc.Y -= sword.YOffset; } } rc.X += _text.Words[w].Width; } iword = newword; } if (newLine) break; } } }