Introduction
Recently I have been
searching internet on how to show subscripts and
superscripts in the device context (when using TextOut
or ExtTextOut
functions). But I could not
find anything. So finally I decided to write the
function myself.
Features and how to
use
My function SSTextOut
has the similar functionality to ExtTextOut
.
You need to specify the pointer to the device context,
the pointer to bounding rectangle, the string itself,
and the justification mode.
The string should
contain special formatting codes - "^"
for superscript and "_" for subscript. The
next symbol after "^" or "_" wil be
shown as subscript or superscript. If you need to show ^
or _ themselves - just type them twice - "^^"
or "__".
Justification can be DT_CENTER
,
DT_LEFT
, or DT_RIGHT
. It
affects only horizontal justification. Vertically, the
text will be centered in the bounding rectangle
automatically. The text outside the rectangle is
clipped. The function uses the current font of the
specified device context.
So, to draw the
meaningless text in the image above you need to call:
SSTextOut(pDC,"ms^2/Hz+H_2O-mc^^2__4",&rect,DT_CENTER);
Source code
Below is the source
code of SSTextOut:
Collapse
void SSTextOut(CDC* pDC, CString data , CRect* drawRect, int justification)
{
//Neccessary initializations
pDC->SaveDC();
CSize sz;
CRect outRect(0,0,0,0);
CFont* pFont = pDC->GetCurrentFont();
CFont* oldFont;
pDC->SetTextAlign(TA_BOTTOM|TA_LEFT);
LOGFONT lf;
pFont->GetLogFont(&lf);
CPoint sub,sup,subofs,supofs;
// Calculate subscript/superscript size and offsets
sub.x=lf.lfWidth/2;
sup.x=lf.lfWidth/2;
sub.y=lf.lfHeight/3*2;
sup.y=lf.lfHeight/3*2;
subofs.x=lf.lfWidth/2;
supofs.x=lf.lfWidth/2;
subofs.y=lf.lfHeight/6;
supofs.y=lf.lfHeight/3;
lf.lfWidth=sub.x;
lf.lfHeight=sub.y;
CFont SubFont;
SubFont.CreateFontIndirect(&lf);
lf.lfWidth=sup.x;
lf.lfHeight=sup.y;
CFont SupFont;
SupFont.CreateFontIndirect(&lf);
CString temp = data;
TCHAR c;
// Calculate the size of the text that needs to be displayed
do
{
int x=0;
CString s = "";
c=' ';
bool bFind=true;
// Find the first "^" or "_", indicating the sub- or superscript
while (bFind)
{
x=data.FindOneOf("^_");
if (x==-1)
{
bFind=false;
x=data.GetLength();
}
else if (x==data.GetLength()-1) bFind=false;
else if (data[x]!=data[x+1])
{
bFind=false;
c=data[x];
}
else x++;
s=s+data.Left(x);
data.Delete(0,min(x+1,data.GetLength()));
}
sz = pDC->GetTextExtent(s);
outRect.right+=sz.cx;
if (outRect.Height()<sz.cy) outRect.top=outRect.bottom-sz.cy;
switch (c)
{
case '^':
oldFont = pDC->SelectObject(&SupFont);
sz = pDC->GetTextExtent(data[0]);
outRect.right+=sz.cx+supofs.x;
data.Delete(0);
pDC->SelectObject(oldFont);
break;
case '_':
oldFont = pDC->SelectObject(&SubFont);
sz = pDC->GetTextExtent(data[0]);
outRect.right+=sz.cx+subofs.x;
data.Delete(0);
pDC->SelectObject(oldFont);
break;
}
}
while (c!=' ');
// Adjust text position
outRect.bottom+=2*subofs.y;
outRect.top-=2*subofs.x;
CPoint Origin;
Origin.y = drawRect->Height()/2+outRect.Height()/2+drawRect->top;
switch (justification)
{
case DT_CENTER:
Origin.x = drawRect->Width()/2-outRect.Width()/2+drawRect->left;
break;
case DT_LEFT:
Origin.x = drawRect->left;
break;
case DT_RIGHT:
Origin.x = drawRect->right-outRect.Width();
}
CPoint pnt = Origin;
data = temp;
// Draw text
do
{
int x=0;
CString s = "";
c=' ';
bool bFind=true;
// Find the first "^" or "_", indicating the sub- or superscript
while (bFind)
{
x=data.FindOneOf("^_");
if (x==-1)
{
bFind=false;
x=data.GetLength();
}
else if (x==data.GetLength()-1) bFind=false;
else if (data[x]!=data[x+1])
{
bFind=false;
c=data[x];
}
else x++;
s=s+data.Left(x);
data.Delete(0,min(x+1,data.GetLength()));
}
// Draw main text
pDC->ExtTextOut(pnt.x,pnt.y,ETO_CLIPPED,drawRect,s,NULL);
sz = pDC->GetTextExtent(s);
pnt.x+=sz.cx;
// Draw subscript or superscript
switch (c)
{
case '^':
oldFont = pDC->SelectObject(&SupFont);
pDC->ExtTextOut(pnt.x+supofs.x,pnt.y-supofs.y,ETO_CLIPPED,drawRect,data[0],NULL);
sz = pDC->GetTextExtent(data[0]);
pnt.x+=sz.cx+supofs.x;
data.Delete(0);
pDC->SelectObject(oldFont);
break;
case '_':
oldFont = pDC->SelectObject(&SubFont);
pDC->ExtTextOut(pnt.x+subofs.x,pnt.y+subofs.y,ETO_CLIPPED,drawRect,data[0],NULL);
sz = pDC->GetTextExtent(data[0]);
pnt.x+=sz.cx+supofs.x;
data.Delete(0);
pDC->SelectObject(oldFont);
break;
}
}
while (c!=' ');
// Done, restoring the device context
pDC->RestoreDC(-1);
}