Click here to Skip to main content
15,886,578 members
Articles / Desktop Programming / MFC
Article

Using Subscripts and Superscripts When Showing Text in the Device Context

Rate me:
Please Sign up or sign in to vote.
4.54/5 (12 votes)
10 Jan 2006CPOL 61K   749   18   5
Extended version of ExtTextOut supporting subscripts and superscripts
Sample Image - SSTextOut.jpg

Introduction

Recently I have been searching The Code Project 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 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 _ will 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:

C++
SSTextOut(pDC,"ms^2/Hz+H_2O-mc^^2__4",&rect,DT_CENTER);

Source Code

The source code of SSTextOut is shown below:

C++
void SSTextOut(CDC* pDC, CString data , CRect* drawRect, int justification)
{
 //Necessary 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);
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Kazakstan Kazakstan
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Questionhow do you know that these are the correct positions of the text Pin
deema_12315-Aug-10 20:48
deema_12315-Aug-10 20:48 
AnswerRe: how do you know that these are the correct positions of the text Pin
Victor Ricklefs15-Aug-10 21:23
Victor Ricklefs15-Aug-10 21:23 
GeneralWell done. Pin
Rob Bryce24-Sep-09 16:17
Rob Bryce24-Sep-09 16:17 
Just what I'm looking for. Did a small tweak to handle font sizes which were negative (made subscript superscript and vice versa) and all was good!

Thanks
Generallatex Pin
umeca7418-Jan-06 3:51
umeca7418-Jan-06 3:51 
AnswerRe: latex Pin
Victor Ricklefs19-Jan-06 10:39
Victor Ricklefs19-Jan-06 10:39 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.