protected void Interpret(Graphics g) { this._isMeasureInSync = false; // if structure is changed, the measure is out of sync char[] searchchars = new Char[] { '\\', '\r', '\n', ')' }; // Modification of StringFormat is necessary to avoid // too big spaces between successive words StringFormat strfmt = (StringFormat)StringFormat.GenericTypographic.Clone(); strfmt.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces; strfmt.LineAlignment = StringAlignment.Far; strfmt.Alignment = StringAlignment.Near; // next statement is necessary to have a consistent string length both // on 0 degree rotated text and rotated text // without this statement, the text is fitted to the pixel grid, which // leads to "steps" during scaling g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; MeasureFont(g, _font, out _cyBaseLineSpace, out _cyBaseAscent, out _cyBaseDescent); System.Collections.Stack itemstack = new System.Collections.Stack(); Font currFont = (Font)_font.Clone(); if(null!=_cachedTextLines) _cachedTextLines.Clear(); // delete old contents else _cachedTextLines = new TextLine.TextLineCollection(); TextLine currTextLine = new TextLine(); // create a new text line first _cachedTextLines.Add(currTextLine); int currTxtIdx = 0; TextItem currTextItem = new TextItem(currFont); // TextItem firstItem = currTextItem; // preserve the first item currTextLine.Add(currTextItem); while(currTxtIdx<_text.Length) { // search for the first occurence of a backslash int bi = _text.IndexOfAny(searchchars,currTxtIdx); if(bi<0) // nothing was found { // move the rest of the text to the current item currTextItem.Text += _text.Substring(currTxtIdx,_text.Length-currTxtIdx); currTxtIdx = _text.Length; } else // something was found { // first finish the current item by moving the text from // currTxtIdx to (bi-1) to the current text item currTextItem.Text += _text.Substring(currTxtIdx,bi-currTxtIdx); if('\r'==_text[bi]) // carriage return character : simply ignore it { // simply ignore this character, since we search for \n currTxtIdx=bi+1; } else if('\n'==_text[bi]) // newline character : create a new line { currTxtIdx = bi+1; // create a new line currTextLine = new TextLine(); _cachedTextLines.Add(currTextLine); // create also a new text item currTextItem = new TextItem(currTextItem,null); currTextLine.Add(currTextItem); } else if('\\'==_text[bi]) // backslash : look what comes after { if(bi+1<_text.Length && (')'==_text[bi+1] || '\\'==_text[bi+1])) // if a closing brace or a backslash, take these as chars { currTextItem.Text += _text[bi+1]; currTxtIdx = bi+2; } // if the backslash not followed by a symbol and than a (, else if(bi+3<_text.Length && !char.IsSeparator(_text,bi+1) && '('==_text[bi+2]) { switch(_text[bi+1]) { case 'b': case 'B': { itemstack.Push(currTextItem); currTextItem = new TextItem(currTextItem, new Font(currTextItem.Font.FontFamily,currTextItem.Font.Size,currTextItem.Font.Style | FontStyle.Bold, GraphicsUnit.World)); currTextLine.Add(currTextItem); currTxtIdx = bi+3; } break; // bold case 'i': case 'I': { itemstack.Push(currTextItem); currTextItem = new TextItem(currTextItem, new Font(currTextItem.Font.FontFamily,currTextItem.Font.Size,currTextItem.Font.Style | FontStyle.Italic, GraphicsUnit.World)); currTextLine.Add(currTextItem); currTxtIdx = bi+3; } break; // italic case 'u': case 'U': { itemstack.Push(currTextItem); currTextItem = new TextItem(currTextItem, new Font(currTextItem.Font.FontFamily,currTextItem.Font.Size,currTextItem.Font.Style | FontStyle.Underline, GraphicsUnit.World)); currTextLine.Add(currTextItem); currTxtIdx = bi+3; } break; // underlined case 's': case 'S': // strikeout { itemstack.Push(currTextItem); currTextItem = new TextItem(currTextItem, new Font(currTextItem.Font.FontFamily,currTextItem.Font.Size,currTextItem.Font.Style | FontStyle.Strikeout, GraphicsUnit.World)); currTextLine.Add(currTextItem); currTxtIdx = bi+3; } break; // end strikeout case 'g': case 'G': { itemstack.Push(currTextItem); currTextItem = new TextItem(currTextItem, new Font("Symbol",currTextItem.Font.Size,currTextItem.Font.Style, GraphicsUnit.World)); currTextLine.Add(currTextItem); currTxtIdx = bi+3; } break; // underlined case '+': case '-': { itemstack.Push(currTextItem); // measure the current font size float cyLineSpace,cyAscent,cyDescent; MeasureFont(g,currTextItem.Font,out cyLineSpace, out cyAscent, out cyDescent); currTextItem = new TextItem(currTextItem, new Font(currTextItem.Font.FontFamily,0.65f*currTextItem.Font.Size,currTextItem.Font.Style, GraphicsUnit.World)); currTextLine.Add(currTextItem); currTextItem.m_SubIndex += ('+'==_text[bi+1] ? 1 : -1); if('-'==_text[bi+1]) currTextItem.m_yShift += 0.15f*cyAscent; // Carefull: plus (+) means shift down else currTextItem.m_yShift -= 0.35f*cyAscent; // be carefull: minus (-) means shift up currTxtIdx = bi+3; } break; // underlined case 'l': // Plot Curve Symbol case 'L': { // parse the arguments // either in the Form // \L(PlotCurveNumber) or // \L(LayerNumber, PlotCurveNumber) or // \L(LayerNumber, PlotCurveNumber, DataPointNumber) // find the corresponding closing brace int closingbracepos = _text.IndexOf(")",bi+1); if(closingbracepos<0) // no brace found, so threat this as normal text { currTextItem.Text += _text.Substring(bi,3); currTxtIdx += 3; continue; } // count the commas between here and the closing brace to get // the number of arguments int parsepos=bi+3; int[] arg = new int[3]; int args; for(args=0;args<3 && parsepos<closingbracepos;args++) { int commapos = _text.IndexOf(",",parsepos,closingbracepos-parsepos); int endpos = commapos>0 ? commapos : closingbracepos; // the end of this argument try { arg[args]=System.Convert.ToInt32(_text.Substring(parsepos,endpos-parsepos)); } catch(Exception) { break; } parsepos = endpos+1; } if(args==0) // if not successfully parsed at least one number { currTextItem.Text += _text.Substring(bi,3); currTxtIdx += 3; continue; // handle it as if it where normal text } // itemstack.Push(currTextItem); // here we don't need to put the item on the stack, since we pared until the closing brace currTextItem = new TextItem(currTextItem,null); currTextLine.Add(currTextItem); currTextItem.SetAsSymbol(args,arg); currTextItem = new TextItem(currTextItem,null); // create a normal text item behind the symbol item currTextLine.Add(currTextItem); // to have room for the following text currTxtIdx = closingbracepos+1; } break; // curve symbol case '%': // Plot Curve Name { // parse the arguments // either in the Form // \%(PlotCurveNumber) or // \%(LayerNumber, PlotCurveNumber) or Match match; int layerNumber=-1; int plotNumber=-1; string plotLabelStyle=null; bool plotLabelStyleIsPropColName=false; if((match = _regexIntArgument.Match(_text,bi+2)).Success) { plotNumber = int.Parse(match.Result("${argone}")); } else if((match = _regexIntIntArgument.Match(_text,bi+2)).Success) { layerNumber = int.Parse(match.Result("${argone}")); plotNumber = int.Parse(match.Result("${argtwo}")); } else if((match = _regexIntQstrgArgument.Match(_text,bi+2)).Success) { plotNumber = int.Parse(match.Result("${argone}")); plotLabelStyle = match.Result("${argtwo}"); plotLabelStyleIsPropColName=true; } else if((match = _regexIntStrgArgument.Match(_text,bi+2)).Success) { plotNumber = int.Parse(match.Result("${argone}")); plotLabelStyle = match.Result("${argtwo}"); } else if((match = _regexIntIntStrgArgument.Match(_text,bi+2)).Success) { layerNumber = int.Parse(match.Result("${argone}")); plotNumber = int.Parse(match.Result("${argtwo}")); plotLabelStyle = match.Result("${argthree}"); } else if((match = _regexIntIntQstrgArgument.Match(_text,bi+2)).Success) { layerNumber = int.Parse(match.Result("${argone}")); plotNumber = int.Parse(match.Result("${argtwo}")); plotLabelStyle = match.Result("${argthree}"); plotLabelStyleIsPropColName=true; } if(match.Success) { itemstack.Push(currTextItem); currTextItem = new TextItem(currTextItem,null); currTextLine.Add(currTextItem); currTextItem.SetAsPlotCurveName(layerNumber,plotNumber,plotLabelStyle,plotLabelStyleIsPropColName); currTextItem = new TextItem(currTextItem,null); // create a normal text item behind the symbol item currTextLine.Add(currTextItem); // to have room for the following text currTxtIdx = bi+2+match.Length; } else { currTextItem.Text += _text.Substring(bi,2); currTxtIdx += 3; continue; // handle it as if it where normal text } } break; // percent symbol default: // take the sequence as it is currTextItem.Text += _text.Substring(bi,3); currTxtIdx = bi+3; break; } // end of switch } else // if no formatting and also no closing brace or backslash, take it as it is { currTextItem.Text += _text[bi]; currTxtIdx = bi+1; } } // end if it was a backslash else if(')'==_text[bi]) // closing brace { // the formating is finished, we can return to the formating of the previous section if(itemstack.Count>0) { TextItem preservedprevious = (TextItem)itemstack.Pop(); currTextItem = new TextItem(preservedprevious,null); currTextLine.Add(currTextItem); currTxtIdx = bi+1; } else // if the stack is empty, take the brace as it is, and use the default style { currTextItem.Text += _text[bi]; currTxtIdx = bi+1; } } } } // end of while loop this._isStructureInSync=true; // now the text was interpreted }