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.
The following files and
classes are included into the source
code :
Core Data Structure
bintree.cpp,
bintree.h |
CBinTree |
The
binary-tree datastructure. |
node.cpp, node.h |
CNode |
The
core node datastructure. |
nodeentities.cpp,
nodeentities.h |
see table 1) |
The
special node entities. |
bintreeformat.cpp,
bintreeformat.h |
CBinTreeFormat ,
CFormatInfoOb |
Formatting
information |
undo.h |
CUndo |
Undo/Redo
functions |
Editing and
Visualizing
formuladlg.cpp,
formuladlg.h, formuladlg_toolbar.cpp |
CFormulaDlg |
A
Dialog that holds a CFormulaCtrl and
toolbar-buttons supporting formula-editing.
The dialog provides Callback-functions which
handle the CToolBarBtn notifications |
formulactrl.cpp,
formulactrl.h |
CFormulaCtrl |
Custom
control that
handles keyboard- and mouse-input. |
formulainplaceedit.cpp,
formulainplaceedit.h |
CFormulaInPlaceEdit |
Inplace
Edit-Control. Behaves like inplace-edit control
in CGridCtrl |
formuladroptarget.cpp,
formuladroptarget.h |
CFormulaDropTarget |
The
drop target for the formula-control |
matrixdlg.cpp,
matrixdlg.h |
CMatrixDlg |
A
Subdialog for parametrizing matrix dimensions. |
formulasettingsdialog.cpp,
formulasettingsdialog.h |
CFormulaSettingsDlg |
Sub
dialog supporting the customizing of the formula
settings (eg. colours, fonts ...) |
Helper classes
fontcombobox.cpp,
fontcombobox.h |
CFontCombo |
A
CComboBox
derived control supporting fontselection. |
colourpicker.cpp,
colourpicker.h |
CColourPicker |
A
CButton
derived control supporting colour-selection. |
colourpopup.cpp,
colourpopup.h |
CColourPopup |
A
CWnd derived
control supporting colour-selection (used by
CColourPicker). |
toolbarbtn.cpp,
toolbarbtn.h |
CToolBarBtn |
A
CButton
derived control supporting the bitmap-based
node-entity selections. |
toolbarbtnctrl.cpp,
toolbarbtnctrl.h, toolbardlg.cpp, toolbardlg.h |
CToolBarBtnCtrl ,
CToolBarDlg |
used
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.
Algorithm |
Binary tree |
Output |
inorder
traversal through a binary tree
inorder (node)
{
inorder (left_child);
process (this);
inorder (right_child);
} |
|
|
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:
- Define a new
node-type (insert a new unique
NT_*
define into the node.h)
- Declare a new
node-entity in the nodeentities.h (derive it public
from
CNode)
class CMyNode
: public CNode
- 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);
- Insert a new button
into a already present ToolbarBtn or build a new
ToolbarBtn with your own node
- 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
class |
Type |
Left Child |
Right Child |
CNode |
NT_STANDARD |
|
|
CNablaNode |
NT_NABLA |
NULL |
CIndexNode |
CIndexNode |
NT_INDEX |
Superscript |
Subscript |
CPartialDerivativeNode |
NT_PARTDERIVE |
Derivation
variable |
Content of the
derivation |
CDerivativeNode |
NT_DERIVE |
Derivation
variable |
Content of the
derivation |
CPlaceHolderNode |
NT_PLACEHOLDER |
NULL |
CIndexNode |
CNthRootNode |
NT_NTHROOT,
NT_ROOT |
Content of the
root |
Basis |
CPowerToNode |
NT_POWERTO |
Basis |
Exponent |
CSumNode |
NT_SUM |
CRangeNode |
Content of the
Sum
|
CProdNode |
NT_PROD |
CRangeNode |
Content of the
Product |
CRangeNode |
NT_RANGE |
Upper Range |
Lower Range |
CIntegrandNode |
NT_INTEGRAND |
Content of the
integral |
Integration
variable |
CLimesNode |
NT_LIMES |
COperatorNode |
Content of the
limes |
CBinomialNode |
NT_BINOMIAL |
Upper |
Lower |
CMatrixNode |
NT_MATRIX |
CLineNode |
NULL |
CLineNode |
NT_LINE |
CLineNode |
CElementNode |
CElementNode |
NT_ELEMENT |
Content of the
Matrixelement |
CElementNode |
CValueNode |
|
|
|
CVariableNode |
NT_VARIABLE |
NULL |
CIndexNode |
CConstantNode |
NT_CONSTANT |
NULL |
CIndexNode |
CInfinityNode |
NT_INFINITY |
NULL |
CIndexNode |
CPlanckNode |
NT_PLANCK |
NULL |
CIndexNode |
CLambdaNode |
NT_LAMBDA |
NULL |
CIndexNode |
CNumberNode |
NT_NUMBER |
NULL |
CIndexNode |
CTypedNode |
|
|
|
CFunctionNode |
|
|
|
CUserFuncNode |
NT_USERFUNCTION |
CBraceNode |
NULL |
CFuncNode |
NT_FUNC |
CBraceNode |
NULL |
CExtFuncNode |
NT_EXTFUNC |
CBraceNode |
NULL |
COpNode |
|
|
|
CDivisionNode |
NT_DIVISION |
Left hand side |
Right hand side |
CEquationNode |
NT_EQUATION |
Left hand side |
Right hand side |
COperatorNode |
NT_OPERATOR |
Left hand side |
Right hand side |
CBraceNode |
NT_BRACE |
Content of the
brace |
NULL |
CPoisonNode |
NT_POISON |
* |
* |
CVectorNode |
NT_VECTOR |
Content of the
Vector |
NULL |
CIntegralNode |
NT_INTEGRAL |
CRangeNode |
CIntegrandNode |
COverlineNode |
NT_OVERLINE |
* |
* |
CArrowNode |
NT_ARROWS |
Left hand side |
Right hand side |
CPlusNode |
NT_PLUS |
Left hand side |
Right hand side |
CMinusNode |
NT_MINUS |
Left hand side |
Right hand side |
CTimesNode |
NT_TIMES |
Left hand side |
Right hand side |
CCrossNode |
NT_CROSS |
Left hand side |
Right 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_pRootNode |
The
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)
void
ReplaceNode(CNode*, CNode*)
CNode* ReplaceSubTree(CNode*, CString)
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)
CNode* SwapLeftChildNode(CNode*, CNode*)
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_pParent |
Pointer
to parent. |
CNode*
m_pLeftChild |
Pointer
to left child. |
CNode*
m_pRightChild |
Pointer
to right child. |
int
m_nAssociativityLevel |
assoicativity
level for mathematical analysis |
DWORD
m_dwEditMode |
edit
mode of the node (one of the NE_* defines) |
int
m_nSubLevel |
sublevel
(subscript, sub-subscript ...) |
int
m_nSubLevelLeftInc
int
m_nSubLevelRightInc |
the
increments of the sublevel for the children |
CString
m_strNodeType |
node
type (one of the NT_* defines) |
CString
m_strShortCut |
the
shortcut of the node (sin for sinus) |
CString
m_strName |
the
name of the node (sinus for sinus) |
COLORREF
m_crColor |
color
of the node (modified by the formatter class) |
LOGFONT
m_lf |
LOGFONT
node (modified by the formatter class) |
CStringArray
m_saKeyWord |
Keywords
are stored in a Stringarray (Use the define LT_*
to access) |
CRect
m_NodeRect |
the
destination rectangle for the ouput |
int
m_nBaseLine |
the
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&,
CNode*, DWORD)
virtual CNode*
GetNodeFromPoint(CDC*, CRect&,
CPoint)
virtual void
FormatNode(
CBinTreeFormat* pFormat=NULL)
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,
CBinTree* pTree) |
function
to overload by subentities |
virtual
void
TransformRects(CRect&, CRect&,
CRect&, CRect&)
virtual CRect
GetContentRect(CDC* pDC)
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 |
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
- Source
code 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