Click here to Skip to main content
15,868,141 members
Articles / Desktop Programming / MFC
Article

Formula Editor

Rate me:
Please Sign up or sign in to vote.
4.98/5 (306 votes)
15 Apr 20039 min read 557K   14.7K   361   83
Formula-editor for editing and exporting mathematical content

 FormulaDlg Image Settings Image

We needed a mathematical formula editor that was able to export the content of the formulas into a programming language (FORTRAN 77 in our case). Therefore we developed a set of classes described below.

Parts of the code are based on the work of

  • Chris Maunder (CGridCtrl, CColourPopup),
  • Alexander Bischofberger (CColourPopup),
  • Matt Weagle (CFormulaInplaceEdit),
  • Norm Almond (CFontCombo),
  • Shekar Narayanan and S. D. Rajan (CToolBarBtn),
  • Keith Rule (CUndo)
Thanks to you for your excellent work.

General appearance

The following files and classes are included into the source code :

Core Data Structure

bintree.cpp, bintree.hCBinTreeThe binary-tree datastructure.
node.cpp, node.hCNodeThe core node datastructure.
nodeentities.cpp, nodeentities.hsee table 1)The special node entities.
bintreeformat.cpp, bintreeformat.hCBinTreeFormat, CFormatInfoObFormatting information
undo.hCUndoUndo/Redo functions
 

Editing and Visualizing

formuladlg.cpp, formuladlg.h, formuladlg_toolbar.cppCFormulaDlgA Dialog that holds a CFormulaCtrl and toolbar-buttons supporting formula-editing. The dialog provides Callback-functions which handle the CToolBarBtn notifications
formulactrl.cpp, formulactrl.hCFormulaCtrlCustom control that handles keyboard- and mouse-input.
formulainplaceedit.cpp, formulainplaceedit.hCFormulaInPlaceEditInplace Edit-Control. Behaves like inplace-edit control in CGridCtrl
formuladroptarget.cpp, formuladroptarget.hCFormulaDropTargetThe drop target for the formula-control
matrixdlg.cpp, matrixdlg.hCMatrixDlgA Subdialog for parametrizing matrix dimensions.
formulasettingsdialog.cpp, formulasettingsdialog.hCFormulaSettingsDlgSub dialog supporting the customizing of the formula settings (eg. colours, fonts ...)

Helper classes

fontcombobox.cpp, fontcombobox.hCFontComboA CComboBox derived control supporting fontselection.
colourpicker.cpp, colourpicker.hCColourPickerA CButton derived control supporting colour-selection.
colourpopup.cpp, colourpopup.hCColourPopupA CWnd derived control supporting colour-selection (used by CColourPicker).
toolbarbtn.cpp, toolbarbtn.hCToolBarBtnA CButton derived control supporting the bitmap-based node-entity selections.
toolbarbtnctrl.cpp, toolbarbtnctrl.h, toolbardlg.cpp, toolbardlg.hCToolBarBtnCtrl, CToolBarDlgused by CToolBarBtn

The basic approach of the formula-editor is the representation of mathematical content in a binary-tree data-structure. the extraction of the content is performed by an inorder-traversal through the binary tree.

AlgorithmBinary treeOutput
inorder traversal through a binary tree
inorder (node)<BR>{<BR>inorder (left_child);<BR>process (this);<BR>inorder (right_child);<BR>}
Node ClassesNode Classes

The base class CNode was originally designed as an abstract base class, but it currently provides the standard behaviour of a node. (draw my left child on the left, draw my right child on the right and draw my own content into the middle). If you want to integrate a new node you have to do the following steps:

  1. Define a new node-type (insert a new unique NT_* define into the node.h)
  2. Declare a new node-entity in the nodeentities.h (derive it public from CNode)
    class CMyNode : public CNode
  3. Implement the methods
    virtual void Serialize(CArchive& ar, CBinTree* pTree);
    virtual void TransformRects(CRect& ,CRect& ,CRect& ,CRect& );
    virtual CRect GetContentRect(CDC* pDC);
    virtual void DrawContent(CDC* pDC, CRect rect, DWORD dwSelect);
  4. Insert a new button into a already present ToolbarBtn or build a new ToolbarBtn with your own node
  5. Handle the ToolBarCtrlSelected Event for your node (in the FormulaDlg_ToolBar.cpp file)

Please have a look on the implementation of the already integrated nodes for further details. Here is a list of them and ther interdependencies:

Node classTypeLeft ChildRight Child
CNodeNT_STANDARD
CNablaNodeNT_NABLANULLCIndexNode
CIndexNodeNT_INDEXSuperscriptSubscript
CPartialDerivativeNodeNT_PARTDERIVEDerivation variableContent of the derivation
CDerivativeNodeNT_DERIVEDerivation variableContent of the derivation
CPlaceHolderNodeNT_PLACEHOLDERNULLCIndexNode
CNthRootNodeNT_NTHROOT, NT_ROOTContent of the rootBasis
CPowerToNodeNT_POWERTOBasisExponent
CSumNodeNT_SUMCRangeNode

Content of the Sum

CProdNodeNT_PRODCRangeNodeContent of the Product
CRangeNodeNT_RANGEUpper RangeLower Range
CIntegrandNodeNT_INTEGRANDContent of the integralIntegration variable
CLimesNodeNT_LIMESCOperatorNodeContent of the limes
CBinomialNodeNT_BINOMIALUpperLower
CMatrixNodeNT_MATRIXCLineNodeNULL
CLineNodeNT_LINECLineNodeCElementNode
CElementNodeNT_ELEMENTContent of the MatrixelementCElementNode
CValueNode
CVariableNodeNT_VARIABLENULLCIndexNode
CConstantNodeNT_CONSTANTNULLCIndexNode
CInfinityNodeNT_INFINITYNULLCIndexNode
CPlanckNodeNT_PLANCKNULLCIndexNode
CLambdaNodeNT_LAMBDANULLCIndexNode
CNumberNodeNT_NUMBERNULLCIndexNode
CTypedNode
CFunctionNode
CUserFuncNodeNT_USERFUNCTIONCBraceNodeNULL
CFuncNodeNT_FUNCCBraceNodeNULL
CExtFuncNodeNT_EXTFUNCCBraceNodeNULL
COpNode
CDivisionNodeNT_DIVISIONLeft hand sideRight hand side
CEquationNodeNT_EQUATIONLeft hand sideRight hand side
COperatorNodeNT_OPERATORLeft hand sideRight hand side
CBraceNodeNT_BRACEContent of the braceNULL
CPoisonNodeNT_POISON**
CVectorNodeNT_VECTORContent of the VectorNULL
CIntegralNodeNT_INTEGRALCRangeNodeCIntegrandNode
COverlineNodeNT_OVERLINE**
CArrowNodeNT_ARROWSLeft hand sideRight hand side
CPlusNodeNT_PLUSLeft hand sideRight hand side
CMinusNodeNT_MINUSLeft hand sideRight hand side
CTimesNodeNT_TIMESLeft hand sideRight hand side
CCrossNodeNT_CROSSLeft hand sideRight hand side
table 1) List of already integrated nodes and their dependecies

Please see the implemented TransformRect and DrawContent methods as an example! There are a lot of ways to code them much better. Any suggestions and refinements are welcome.

If you want to use this code in your project you only have to import the classes and to call the DoModal-method of the FormulaDlg.Please be careful with the resources. The resources for the toolbar of the formula-dialog are included via compiletime-directives (resource includes-submenu in the view -menu of the developer-studio)

#include "mathsym.h"
#include "mathsym.rc"
#include "FormulaDlg.h"

void CMainFrame::OnFormula() 
{
    CFormulaDlg FormulaDlg;
    FormulaDlg.DoModal();
}

The core-classes with there attributes and methods look as follow:

CBinTree

CNode* m_pRootNodeThe rootnode of the tree.
CNode* m_pSelectNode The selected node.
DWORD m_dwSelectType The node-selection type (one of NS_*, see node.h).
CString m_strName The name of the tree.
CNode* CreateTree(CString strType) Creates a tree with a root node of type strType.
CNode* GetRootNode() Returns the root node.
void SetRootNode(CNode* pNode) Sets the root node.
void SetName(CString) Sets the Name of the Bintree.
CString GetName() Returns the name of the Bintree.
void SelectNode(CNode* pNode, DWORD dwSelectType) Selects the node pNode with nodeselectiontype dwSelectType.
CNode* GetSelectedNode() Returns the selected node.
void SetNodeSelectionType(DWORD dwSelectType) Sets the nodeselectiontype for the tree.
void GetNodeSelectionType(DWORD dwSelectType) Returns the nodeselectiontype for the tree.
void ResetTree() Resets the tree and delete all nodes.
CNode* GetParent(CNode* pNode) Returns the parent of node pNode.
CNode* CreateNode(CString strType) Creates a node of type strType.
CNode* ReplaceNode(CNode*, CString)<BR>void ReplaceNode(CNode*, CNode*)<BR>CNode* ReplaceSubTree(CNode*, CString)<BR>CNode* InsertNode(CNode*, CNode*, CString, DWORD ) Some handy functions for rearrangement of the tree.
void DrawTree(CDC* pDC, CRect rect) Draws the tree on a dc.
CRect GetRect(CDC* pDC) Returns the destination-rect of the tree.
CNode* GetNodeFromPoint(CDC*, CRect&, CPoint) Returns a node that draws itself into a rect (resultRect) that contains point.
void ReformatNodes(CBinTreeFormat* pFormat=NULL) Reformat the tree with a special formatter.
void SortPreOrder(CNode* pOldNode)<BR>CNode* SwapLeftChildNode(CNode*, CNode*)<BR>CNode* SwapRightChildNode(CNode*, CNode*) Sorting the tree in associative order (currently not used).
BOOL WriteDIB(CString strFile) Writes the binary-tree content into a dib.
BOOL PrintDDB(CDC* pDC) Prints the binary-tree content into a DC.
CString CBinTree::WriteFormula(int nLanguageType) Write the binary-tree content into a CString.
virtual void DeleteContents() Resets the tree and delete all nodes (from CUndo).
void DeleteNode(CNode* pNode) Deletes a node.
CNode* CloneNode(CNode* pNode, BOOLbCloneSubTree) Clones a node with or without its subtree.
 

CNode

CNode* m_pParentPointer to parent.
CNode* m_pLeftChildPointer to left child.
CNode* m_pRightChildPointer to right child.
int m_nAssociativityLevelassoicativity level for mathematical analysis
DWORD m_dwEditModeedit mode of the node (one of the NE_* defines)
int m_nSubLevelsublevel (subscript, sub-subscript ...)
int m_nSubLevelLeftInc<BR>int m_nSubLevelRightIncthe increments of the sublevel for the children
CString m_strNodeTypenode type (one of the NT_* defines)
CString m_strShortCutthe shortcut of the node (sin for sinus)
CString m_strNamethe name of the node (sinus for sinus)
COLORREF m_crColorcolor of the node (modified by the formatter class)
LOGFONT m_lfLOGFONT node (modified by the formatter class)
CStringArray m_saKeyWordKeywords are stored in a Stringarray (Use the define LT_* to access)
CRect m_NodeRectthe destination rectangle for the ouput
int m_nBaseLinethe baseline of the node (with childs )
// e.g. the division line for the CDivisionNode
CString GetNodeType()Returns the node type
void SetParentDirect(CNode* pNode)Sets the parent node directly
CNode* GetParentDirect()Returns the parent node
void SetLeftChild(CNode* pNode)Sets the left child (and sets left child's new parent as this)
CNode* GetLeftChild()Returns the left child
void SetRightChild(CNode* pNode)Sets the right child (and sets right child's new parent as this)
CNode* GetRightChild()Returns the right child
void SetName(CString strName)Sets the name of the node
CString GetName()Returns the name of the node
void SetShortCut(CString strShortCut)Sets the shortcut of the node (used for rendering)
<CODE><CODE>CString GetShortCut()Returns the shortcut of the node
void SetEditMode(DWORD dwEditMode)Sets the edit mode of the node (Combination of NE_ defines)
DWORD GetEditMode()Returns the edit mode of the node
void SetItalic(BOOL bItalic)Sets the italic attribute in the LOGFONT structure
BOOL GetItalic()Returns the italic attribute in the LOGFONT structure
void SetBold(BOOL bBold)Sets the lfWeight-value of the LOGFONT structure (FW_BOLD for bBold==TRUE and FW_NORMAL for bBold==FALSE)
BOOL GetBold()Returns the weight of LOGFONT structure (TRUE for lfWeight==FW_BOLD and FALSE for bBold==FW_NORMAL)
void SetColor(COLORREF crColor)Sets the RGB colour of the node
COLORREF GetColor()Returns the RGB colour of the node
void SetSubLevel(int nSubLevel)Sets the sublevel of the node
int GetSubLevel()Returns the sublevel of the node
int GetSubLevelLeftInc()Returns the sublevel-increment of the left children
int GetSubLevelRightInc()Returns the sublevel-increment of the right children
void SetFaceName(CString strFaceName)Sets the facename in the LOGFONT structure
CString GetFaceName()Returns the facename of the LOGFONT structure as a CString
virtual int GetAssociativityLevel()Returns the Associativity Level of the node (for symbolical postprocessing, currently not used)
virtual BOOL IsNodeLeaf()Returns TRUE if the node has no valid left and right child
virtual void DrawNode(CDC*, CRect&, <BR>                      CNode*, DWORD)<BR>virtual CNode* GetNodeFromPoint(CDC*, CRect&, <BR>                                CPoint)<BR>virtual void FormatNode(<BR>                    CBinTreeFormat* pFormat=NULL)<BR>virtual CRect GetRect(CDC* pDC)drawing functions
CNode* FindParentPraeorder(CNode* pSearchNode)searching praeorder for the parent of a given node
virtual void Serialize(CArchive& ar, <BR>                       CBinTree* pTree)function to overload by subentities
virtual void TransformRects(CRect&, CRect&,<BR>                            CRect&, CRect&)<BR>virtual CRect GetContentRect(CDC* pDC)<BR>virtual void DrawContent(CDC*, CRect, DWORD)standardimplementation (default behaviour)
virtual CString WriteNode(int nLanguageType)Output of the formula in the language LT_*
LOGFONT* GetLogFont()Returns a pointer to the LOGFONT structure m_lf
 

Features

The formula-control has got the following additional features:

  • Copy, cut and paste (currently you are allowed to paste into placeholder-nodes only )
  • Drag & Drop (currently you are allowed to drop onto placeholder-nodes only)
  • Export into a Bitmap
  • Printing and Print-Preview is realized via DDB
  • Sourcecode export (currently only FORTRAN 77 is implemented)

How to use...

Select an equation-node from the equation-toolbar-button. Then you get an equation with placeholders on the left and on the right side. By moving the mouse over the equation the nodes are highlited. Select a placeholder with a single left-mouseclick. Now you can overwrite the placeholder with any node you want. By selecting a node with a double-click, the whole subtree of the node is selcted (e.g select the = from an equation with a doubleclick and either the left and the right side of the equation are selected). If you select a variable-node, a constant-node, a number-node or a userfunction-node you get into the editing by another left-mouseclick.

History

for detailed information please have a look on the file-header-comments
Version 1.0.0.1 - 15-Apr-2003
  • Reduced Flickering (Scrolling and Updating)
  • Drag&Drop refined
  • Modified FormulaInPlaceEdit
  • Added WMF export
  • CRangeNode refined
Version 1.0.0.0 - 09-Apr-2003
First Version

Environment:
Windows NT 4.0 Service Pack 6
MFC Version: 6.0
Service Pack: 5

DataPool engineering
Essener Str. 99
D-46047 Oberhausen

Internet: www.dp-e.de
thorsten.wack@dp-e.de

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


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

Comments and Discussions

 
GeneralGood Pin
zhangliuxue17-Apr-03 16:13
zhangliuxue17-Apr-03 16:13 
Generalbaseline is not correct for squareroot and powerto node for complicate formulas Pin
GE17-Apr-03 14:33
GE17-Apr-03 14:33 
GeneralThe zip file is corrupted! Pin
gzk5555515-Apr-03 1:09
gzk5555515-Apr-03 1:09 
GeneralRe: The zip file is corrupted! Pin
Tim Smith17-Apr-03 7:00
Tim Smith17-Apr-03 7:00 
GeneralRe: The zip file is corrupted! Pin
gzk5555520-Apr-03 16:40
gzk5555520-Apr-03 16:40 
Generalnot bad, but... Pin
Alex Mol14-Apr-03 3:38
Alex Mol14-Apr-03 3:38 
GeneralRe: not bad, but... Pin
tbw14-Apr-03 4:16
tbw14-Apr-03 4:16 
GeneralRe: not bad, but... Pin
Alex Mol14-Apr-03 20:58
Alex Mol14-Apr-03 20:58 
win2000, sp3, ie6
i guess flickering doesn't depends on system settings. keyboard input present, but it is extremely uncomfortable. I didn't want to say that it is bad, i just say it is unfinished work (may be for internal use only). Note, that not all users use mouse input - in your sample there is no way to create formula with keyboard only (may be i miss something?)
GeneralRe: not bad, but... Pin
Paul Selormey15-Apr-03 1:56
Paul Selormey15-Apr-03 1:56 
GeneralGreat work! Pin
User 665813-Apr-03 6:19
User 665813-Apr-03 6:19 
Generalselection bug Pin
Paolo Messina12-Apr-03 20:53
professionalPaolo Messina12-Apr-03 20:53 
GeneralRe: selection bug Pin
tbw13-Apr-03 1:06
tbw13-Apr-03 1:06 
GeneralRe: selection bug Pin
Paolo Messina13-Apr-03 8:26
professionalPaolo Messina13-Apr-03 8:26 
GeneralRe: selection bug Pin
tbw13-Apr-03 21:25
tbw13-Apr-03 21:25 
GeneralGreat!! Pin
Ryan Binns10-Apr-03 18:05
Ryan Binns10-Apr-03 18:05 
GeneralGreat work! Pin
Ai Xing10-Apr-03 17:05
Ai Xing10-Apr-03 17:05 
Generalvery nice! Pin
Roman Nurik10-Apr-03 11:37
Roman Nurik10-Apr-03 11:37 
GeneralRe: very nice! Pin
tbw14-Apr-03 0:58
tbw14-Apr-03 0:58 
GeneralVery Good! Pin
Gary Kirkham10-Apr-03 8:35
Gary Kirkham10-Apr-03 8:35 
GeneralSpeparation of concerns Pin
compiler10-Apr-03 6:07
compiler10-Apr-03 6:07 
GeneralExcellent !!! Pin
9-Apr-03 12:11
suss9-Apr-03 12:11 
GeneralMathML Pin
Rui Dias Lopes9-Apr-03 7:49
Rui Dias Lopes9-Apr-03 7:49 
GeneralRe: MathML Pin
tbw9-Apr-03 22:55
tbw9-Apr-03 22:55 
GeneralAwesome... Pin
BestSnowman9-Apr-03 7:48
BestSnowman9-Apr-03 7:48 
GeneralRe: Awesome... Pin
toxcct29-Jan-05 3:09
toxcct29-Jan-05 3:09 

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.