///
/// This file is part of ILNumerics Community Edition.
///
/// ILNumerics Community Edition - high performance computing for applications.
/// Copyright (C) 2006 - 2012 Haymo Kutschbach, http://ilnumerics.net
///
/// ILNumerics Community Edition is free software: you can redistribute it and/or modify
/// it under the terms of the GNU General Public License version 3 as published by
/// the Free Software Foundation.
///
/// ILNumerics Community Edition is distributed in the hope that it will be useful,
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/// GNU General Public License for more details.
///
/// You should have received a copy of the GNU General Public License
/// along with ILNumerics Community Edition. See the file License.txt in the root
/// of your distribution package. If not, see .
///
/// In addition this software uses the following components and/or licenses:
///
/// =================================================================================
/// The Open Toolkit Library License
///
/// Copyright (c) 2006 - 2009 the Open Toolkit library.
///
/// Permission is hereby granted, free of charge, to any person obtaining a copy
/// of this software and associated documentation files (the "Software"), to deal
/// in the Software without restriction, including without limitation the rights to
/// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
/// the Software, and to permit persons to whom the Software is furnished to do
/// so, subject to the following conditions:
///
/// The above copyright notice and this permission notice shall be included in all
/// copies or substantial portions of the Software.
///
/// =================================================================================
///
using System;
using System.Text;
using System.Drawing;
using System.Collections.Generic;
using ILNumerics.Drawing;
using ILNumerics.Drawing.Interfaces;
namespace ILNumerics.Drawing.Labeling {
///
/// Simple, (partial) tex symbol interpreter
///
/// this is the default interpreter for all ILLabelingElements
public class ILSimpleTexInterpreter : ILSimpleInterpreter {
#region attributes
public static readonly ILKeywords Keywords = new ILKeywords();
#endregion
#region constructor
///
/// create a new instance of a simple text interpreter
///
public ILSimpleTexInterpreter () : base () { }
#endregion
#region helper functions
protected override void parseString (string expression, Font font, Point offset, Color color,
IILTextRenderer renderer, ref Size size,
ref List queue) {
int pos = 0;
string key, itemText;
RectangleF bmpSize = new RectangleF();
int curHeigth = 0, curWidth = 0;
Bitmap itemBMP = null;
int lineHeight = 0, lineWidth = 0;
Size itemSize = Size.Empty;
while (pos < expression.Length) {
itemText = expression.Substring(pos++,1);
#region special position control sequences
if (itemText == "\r") {
queue.Add(new ILRenderQueueItem(itemText,0,0, color));
if (curWidth < lineWidth)
curWidth = lineWidth;
lineWidth = 0;
continue;
} else if (itemText == "\n") {
queue.Add(new ILRenderQueueItem(itemText,0,0, color));
curHeigth += lineHeight;
lineHeight = 0;
if (curWidth < lineWidth)
curWidth = lineWidth;
lineWidth = 0;
continue;
#endregion
} else if (itemText == "\\") {
#region font control
if (pos < expression.Length - 2) {
#region test for font control sequences: \it,\bf,\rm
if (expression[pos] == 'i' && expression[pos+1] == 't') {
font = new Font(font,font.Style | FontStyle.Italic);
pos += 2; continue;
} else if (expression[pos] == 'b' && expression[pos+1] == 'f') {
font = new Font(font,font.Style | FontStyle.Bold);
pos += 2; continue;
} else if (expression[pos] == 'r' && expression[pos+1] == 'm') {
font = new Font(font,FontStyle.Regular);
pos += 2; continue;
}
#endregion
#region fontname,-size,-color
if (parseKeyword(expression,ref pos,Keywords.Reset)) {
color = Color.Empty;
font = m_normalFont;
offset = new Point(0,0);
continue;
}
string parameter = "";
if (parseKeywordArgumented(expression,ref pos,Keywords.Fontname,ref parameter)) {
font = new Font(parameter,font.Size,font.Style,font.Unit);
continue;
}
if (parseKeywordArgumented(expression,ref pos,Keywords.Fontsize,ref parameter)) {
int newSize;
if (!int.TryParse(parameter,out newSize))
continue;
if (parameter.StartsWith("+") && newSize > 0 ) {
newSize += (int)font.Size;
if (newSize > 40) newSize = 40;
} else if (parameter.StartsWith("-") && -newSize < font.Size) {
newSize = (int)font.Size + newSize;
}
if (newSize > 0 && newSize < 40) {
offset.Y += (int)Math.Round(font.Size - newSize);
font = new Font(font.Name,newSize,font.Style,font.Unit);
}
continue;
}
if (parseKeywordArgumented(expression,ref pos,Keywords.Color,ref parameter)) {
parseColor(parameter, ref color);
continue;
}
#endregion
}
#endregion
//if (pos < expression.Length - "size".Length)
#region handle predefined symbols
TextSymbols symbol = matchSymbol(expression,ref pos);
if (symbol != TextSymbols.nothing) {
itemText = TranslateSymbol(symbol);
if (String.IsNullOrEmpty (itemText)) continue;
}
#endregion
#region lower- upper indices
} else if (pos < expression.Length && itemText == "_") {
int end;
if (pos < expression.Length-1 && expression[pos] == '{') {
pos ++;
// find end brace & remove
end = expression.IndexOf('}',pos)-1;
if (end > 0 && end < expression.Length) {
parseString(
expression.Substring(pos,end-pos+1),
new Font(font.Name,font.Size * 0.7f,font.Style,font.Unit),
new Point(offset.X,offset.Y + (int)(0.3f * font.Height)),
color, renderer, ref size, ref queue);
pos = end+2;
continue;
}
}
// cache next char only
parseString(
expression.Substring(pos++,1),
new Font(font.Name,font.Size * 0.7f,font.Style,font.Unit),
new Point(offset.X,offset.Y + (int)(0.3f * font.Height)),
color, renderer, ref size, ref queue);
continue;
} else if (pos < expression.Length && itemText == "^") {
int end;
//offset.Y += 0.8f * font.Height;
if (pos < expression.Length-1 && expression[pos] == '{') {
pos ++;
// find end brace & remove
end = expression.IndexOf('}',pos)-1;
if (end > 0 && end < expression.Length) {
parseString(
expression.Substring(pos,end-pos+1),
new Font(font.Name,font.Size * 0.7f,font.Style,font.Unit),
new Point(offset.X,offset.Y - (int)(0.2f * font.Height)),
color, renderer, ref size, ref queue);
pos = end+2;
continue;
}
}
// cache next char only
parseString(
expression.Substring(pos++,1),
new Font(font.Name,font.Size * 0.7f,font.Style,font.Unit),
new Point(offset.X,offset.Y - (int)(0.2f * font.Height))
,color, renderer, ref size, ref queue);
continue;
#endregion
}
key = ILHashCreator.Hash(font,itemText);
if (renderer.TryGetSize(key, ref itemSize)) {
queue.Add(new ILRenderQueueItem(key,offset,color));
if (itemSize.Height > lineHeight) lineHeight = itemSize.Height;
lineWidth += (int)itemSize.Width;
} else {
lock (this) {
itemBMP = transformItem(itemText,font,out bmpSize);
renderer.Cache(key,itemBMP,bmpSize);
queue.Add(new ILRenderQueueItem(key,offset,color));
// update size
if (bmpSize.Height > lineHeight)
lineHeight = (int)bmpSize.Height;
lineWidth += (int)bmpSize.Width;
}
}
}
size.Width += ((curWidth>lineWidth)?curWidth:lineWidth);
size.Height = curHeigth + lineHeight;
}
private bool parseKeyword(string text, ref int pos, string keyword) {
if (pos < text.Length - keyword.Length
&& text.Substring(pos,keyword.Length) == keyword) {
pos += keyword.Length;
return true;
}
return false;
}
private void parseColor(string parameter, ref Color color) {
if (!String.IsNullOrEmpty(parameter) && parameter[0] == '#') {
// try to parse for rgb value. Format: #D2E540
if (parameter.Length == 7) {
IFormatProvider format = System.Threading.Thread.CurrentThread.CurrentCulture;
byte r,g,b;
// R - value
if (!byte.TryParse(parameter.Substring(1,2),
System.Globalization.NumberStyles.HexNumber,
format,out r)) return;
// G - value
if (!byte.TryParse(parameter.Substring(3,2),
System.Globalization.NumberStyles.HexNumber,
format,out g)) return;
// B - value
if (!byte.TryParse(parameter.Substring(5,2),
System.Globalization.NumberStyles.HexNumber,
format,out b)) return;
color = Color.FromArgb(r,g,b);
}
} else {
// try to parse for known color name
try {
color = Color.FromName(parameter);
} catch {}
}
}
private bool parseKeywordArgumented(string text, ref int pos, string keyword, ref string parameter) {
int tmpPos = pos;
if (pos < text.Length - keyword.Length
&& text.Substring(pos,keyword.Length) == keyword) {
tmpPos = pos+keyword.Length;
if (text[tmpPos] != '{'
|| tmpPos == text.Length-1) return false;
int end = text.IndexOf('}',++tmpPos);
if (end < tmpPos) return false;
parameter = text.Substring(tmpPos,end-tmpPos).Trim();
pos = end + 1;
return true;
}
return false;
}
///
/// extract TextSymbol from text
///
/// text to extract symbol from
/// current text character position
/// one of TextSymbol enumeration values
/// if one symbol was found, its enum representation is
/// returned and pos is increased by the corresponding number of
/// characters. If no matching symbol was found, pos is not altered
/// and TextSymbols.nothing will be returned.
internal static TextSymbols matchSymbol (string text, ref int pos) {
foreach (string sym in Enum.GetNames(typeof(TextSymbols))) {
if (pos <= text.Length - sym.Length) {
if (text.Substring(pos,sym.Length) != sym) {
continue;
}
if (sym == "nothing") continue;
pos += sym.Length;
return (TextSymbols)Enum.Parse(typeof(TextSymbols),sym);
}
}
return TextSymbols.nothing;
}
///
/// translates TextSymbol enum value to unicode character
///
/// enum representation
/// unicode character
/// refers to: http://www.decodeunicode.org/ (e.g.)
public static string TranslateSymbol (TextSymbols symbol) {
#region symbol matching
switch (symbol) {
case TextSymbols.alpha:
return "α";
case TextSymbols.beta:
return "β";
case TextSymbols.gamma:
return "γ";
case TextSymbols.delta:
return "δ";
case TextSymbols.epsilon:
return "ε";
case TextSymbols.zeta:
return "ζ";
case TextSymbols.eta:
return "η";
case TextSymbols.theta:
return "θ";
case TextSymbols.vartheta:
return "\u03d1";
case TextSymbols.iota:
return "ι";
case TextSymbols.kappa:
return "κ";
case TextSymbols.lambda:
return "λ";
case TextSymbols.mu:
return "μ";
case TextSymbols.nu:
return "ν";
case TextSymbols.xi:
return "ξ";
case TextSymbols.pi:
return "π";
case TextSymbols.rho:
return "ρ";
case TextSymbols.sigma:
return "σ";
case TextSymbols.varsigma:
return "ς";
case TextSymbols.tau:
return "τ";
case TextSymbols.upsilon:
return "υ";
case TextSymbols.phi:
return "φ";
case TextSymbols.chi:
return "χ";
case TextSymbols.psi:
return "ψ";
case TextSymbols.omega:
return "ω";
case TextSymbols.Gamma:
return "Γ";
case TextSymbols.Delta:
return "Δ";
case TextSymbols.Theta:
return "Θ";
case TextSymbols.Lambda:
return "Λ";
case TextSymbols.Xi:
return "Ξ";
case TextSymbols.Pi:
return "\u03a0"; //"Π";
case TextSymbols.Sigma:
return "Σ";
case TextSymbols.Upsilon:
return "Υ";
case TextSymbols.Phi:
return "Φ";
case TextSymbols.Psi:
return "Ψ";
case TextSymbols.Omega:
return "Ω";
case TextSymbols.forall:
return "\u2200";
case TextSymbols.exists:
return "\u2203";
case TextSymbols.ni:
return "\u220b";
case TextSymbols.cong:
return "\u2205";
case TextSymbols.neq:
return "\u2260";
case TextSymbols.equiv:
return "\u2261";
case TextSymbols.approx:
return "\u2240";
case TextSymbols.aleph:
return "\u2235";
case TextSymbols.Im:
return "\u2111";
case TextSymbols.Re:
return "\u211b";
case TextSymbols.wp:
return "\u2118";
case TextSymbols.otimes:
return "\u2297";
case TextSymbols.oplus:
return "\u2295";
case TextSymbols.oslash:
return "\u2205";
case TextSymbols.cap:
return "\u22c2";
case TextSymbols.cup:
return "\u22c3";
case TextSymbols.supseteq:
return "\u2287";
case TextSymbols.supset:
return "\u2283";
case TextSymbols.subseteq:
return "\u2286";
case TextSymbols.subset:
return "\u2282";
case TextSymbols.int_:
return "\u222b";
case TextSymbols.in_:
return "\u2208";
case TextSymbols.o:
return "\u25cb";
case TextSymbols.rfloor:
return "\u230b";
case TextSymbols.lceil:
return "\u2308";
case TextSymbols.nabla:
return "\u2207";
case TextSymbols.lfloor:
return "\u230a";
case TextSymbols.cdot:
return "\u2219";
case TextSymbols.ldots:
return "\u2026";
case TextSymbols.cdots:
return "\u220f";
case TextSymbols.perp:
return "\u22a5";
case TextSymbols.neg:
return "\u2511";
case TextSymbols.prime:
return "\u2032";
case TextSymbols.wedge:
return "\u22c0";
case TextSymbols.times:
return "\u2a09";
case TextSymbols.Null:
return "\u2205";
case TextSymbols.rceil:
return "\u2309";
case TextSymbols.surd:
return "\u221a";
case TextSymbols.mid:
return "|";
case TextSymbols.vee:
return "\u22c1";
case TextSymbols.varpi:
return "\u03d6";
case TextSymbols.copyright:
return "\u00a9";
case TextSymbols.langle:
return "\u2329";
case TextSymbols.rangle:
return "\u232a";
case TextSymbols.sim:
return "\u223c";
case TextSymbols.leq:
return "\u2264";
case TextSymbols.infty:
return "\u221e";
case TextSymbols.leftrightarrow:
return "\u21d4";
case TextSymbols.leftarrow:
return "\u21d0";
case TextSymbols.uparrow:
return "\u21d1";
case TextSymbols.rightarrow:
return "\u21d2";
case TextSymbols.downarrow:
return "\u21d3";
case TextSymbols.circ:
return "\u25cc";
case TextSymbols.pm:
return "\u00b1";
case TextSymbols.geq:
return "\u2265";
case TextSymbols.propto:
return "\u221d";
case TextSymbols.partial:
return "\u2202";
case TextSymbols.div:
return "\u00f7";
default:
break;
}
return "";
#endregion
}
#endregion
#region symbol definitions
///
/// available keywords, interpretable by this IILInterpreter
///
/// The static instance ILSimpleTexInterpreter.Keywords can be
/// used to alter the keywords used to switch to different font styles etc.
public class ILKeywords {
private string m_fontname = "fontname";
///
/// placeholder for font name control sequence
///
public string Fontname {
get { return m_fontname; }
set { if (!string.IsNullOrEmpty(value)) m_fontname = value; }
}
private string m_fontsize = "fontsize";
///
/// placeholder for font size control sequence
///
public string Fontsize {
get { return m_fontsize; }
set { if (!string.IsNullOrEmpty(value)) m_fontsize = value; }
}
private string m_italic = "it";
///
/// placeholder for italic font control sequence
///
public string Italic {
get { return m_italic; }
set { if (!string.IsNullOrEmpty(value)) m_italic = value; }
}
private string m_bold = "bf";
///
/// placeholder for bold font control sequence
///
public string Bold {
get { return m_bold; }
set { if (!string.IsNullOrEmpty(value)) m_bold = value; }
}
private string m_color = "color";
///
/// placeholder for font color control sequence
///
public string Color {
get { return m_color; }
set { if (!string.IsNullOrEmpty(value)) m_color = value; }
}
private string m_reset = "reset";
///
/// placeholder for text control sequence 'reset to initial value'
///
public string Reset {
get { return m_reset; }
set { if (!string.IsNullOrEmpty(value)) m_reset = value; }
}
}
#pragma warning disable 1591
///
/// all available TextSymbols (like \\Alpha etc.) this IILTextInterpreter understands
///
public enum TextSymbols {
alpha,
beta,
gamma,
delta,
epsilon,
zeta,
eta,
theta,
vartheta,
iota,
kappa,
lambda,
mu,
nu,
xi,
pi,
rho,
sigma,
varsigma,
tau,
upsilon,
phi,
chi,
psi,
omega,
Gamma,
Delta,
Theta,
Lambda,
Xi,
Pi,
Sigma,
Upsilon,
Phi,
Psi,
Omega,
forall,
exists,
ni,
cong,
neq,
equiv,
approx,
aleph,
Im,
Re,
wp,
otimes,
oplus,
oslash,
cap,
cup,
supseteq,
supset,
subseteq,
subset,
int_,
in_,
o,
rfloor,
lceil,
nabla,
lfloor,
cdot,
ldots,
perp,
neg,
prime,
wedge,
times,
Null,
rceil,
surd,
mid,
vee,
varpi,
copyright,
langle,
rangle,
nothing,
sim,
leq,
infty,
clubsuit,
diamondsuit,
heartsuit,
spadesuit,
leftrightarrow,
leftarrow,
uparrow,
rightarrow,
downarrow,
circ,
pm,
geq,
propto,
partial,
div,
cdots
}
#pragma warning restore 1591
#endregion
}
}