Click here to Skip to main content
15,894,410 members
Articles / Desktop Programming / MFC

Embeddable script editor for MFC applications

Rate me:
Please Sign up or sign in to vote.
4.90/5 (60 votes)
15 Jul 20032 min read 336.7K   6.4K   130  
A library that allows you to embed scripting functionality to your C++ MFC application.
/*********************************************************************

  Copyright (C) 2001 Smaller Animals Software, Inc.
  
	This software is provided 'as-is', without any express or implied
	warranty.  In no event will the authors be held liable for any damages
	arising from the use of this software.
	
	  Permission is granted to anyone to use this software for any purpose,
	  including commercial applications, and to alter it and redistribute it
	  freely, subject to the following restrictions:
	  
		1. The origin of this software must not be misrepresented; you must not
		claim that you wrote the original software. If you use this software
		in a product, an acknowledgment in the product documentation would be
		appreciated but is not required.
		
		  2. Altered source versions must be plainly marked as such, and must not be
		  misrepresented as being the original software.
		  
			3. This notice may not be removed or altered from any source distribution.
			
			  http://www.smalleranimals.com
			  smallest@smalleranimals.com
			  
				--------
				
				  This code is based, in part, on:
				  
					"Syntax Coloring Text Edit Window Class " - Randy More (9, May 1998)
					http://www.codeguru.com/editctrl/syntax_coloring.shtml
					
					  Though probably only 5% of the original code remains.
					  
**********************************************************************/

/////////////////////////////////////////////////////////////////////////////
//Header for the ColorEditWnd class
/////////////////////////////////////////////////////////////////////////////


#ifndef _COLORIZED_VIEW_
#define _COLORIZED_VIEW_

#include "Colorizer.h"
#include "ScriptText.h"
#include "UndoFrame.h"

// Custom messages
#define EN_CURPOSCHANGE		WM_USER + 1
#define EN_CHAR				WM_USER + 2
#define EN_SCROLL			WM_USER + 3
#define EN_CARET			WM_USER + 4

// Structure for our custom messages
typedef struct _NMCLRWND
{
    NMHDR hDR;
	int code1;
	int code2;
} NMCLRWND, *PNMCLRWND, FAR *LPNMCLRWND;


class ColorEditWnd : public CWnd
{
	
public:
	DECLARE_CONTROL(ColorEditWnd, CWnd);
	DECLARE_DYNAMIC(ColorEditWnd);
	
	ColorEditWnd();
	
	ColorEditWnd(CWnd * parent, 
		const CRect & rect,        // where to put it
		int nID,                   // control ID. this control will post messages to the parent
		// (EN_CHANGE, EN_KILLFOCUS, EN_SETFOCUS, etc) with this ID
		
		int iTabSize,              // spaces per tab. all tabs are spaces
		int iFontSize,             // font size in 10ths of a point (uses CreatePointFont)
		const char *pFontName,     // font name. only use this with fixed width fonts!!!!!
		bool bShowHorizScroll = true);    // show the horizontal scroll bar?
	
	
	BOOL Create(DWORD dwFlags,             // recommend : WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL
		CWnd * parent, 
		const CRect & rect,
		int nID, 
		int iTabSize,
		int iFontSize, 
		const char *pFontName);
	
	// this is how we pick up the cut/copy/paste/undo/redo messages
	//
	// feel free to disable this, if you want to control these functions
	// externally.
	void     UseKeyboardAccelerators(bool b)  {m_bUseKBAccel = b;}
	
public:
	///////////////////////////////////////////////////////////////////////////
	// clear all text
	void Reset();
	
	///////////////////////////////////////////////////////////////////////////
	// clear and set text to pInText
	void LoadText(const char *pInText);
	
	// get a single string copy of the contents
	void UnloadText(CString &pText) const;
	
	///////////////////////////////////////////////////////////////////////////
	// number of text lines in the buffer
	_inline int GetLineCount()      {return GetTextSize();}
	
	///////////////////////////////////////////////////////////////////////////
	// position of cursor and anchor. 
	// if these are different positions, the characters between are selected.
	void  SetCursorPos(CPoint pos);
	void  SetAnchorPos(CPoint pos);
	
	_inline CPoint GetCursorPos()   {return CursorPos();}
	_inline CPoint GetAnchorPos()   {return AnchorPos();}
	
	// another way to set selection
	void  SetSelection(int charPos1, int line1, int charPos2, int line2);
	void  ReplaceSelText(const char *pText);
	
	// set this line as the top line in the window
	void ScrollToLine(int iLine);
	
	// scroll if necessary to make this line visible
	void SoftScrollToLine(int iLine);
	
	// scroll the window to show the cursor
	void ScrollToCursor();
	
	// get one line of text
	CString GetLine(int iLine) const      {return GetTextLine(iLine);}
	
	// set a single line of text
	void SetLine(const char *pText, int iLine);
	
	///////////////////////////////////////////////////////////////////////////
	// client rect of the text at a given line
	CRect GetLineRect(int iLine) const;
	
	// client rect that encompasses both lines
	CRect GetLineRect(int iLine1, int iLine2) const;
	
	// number of visible lines. 
	// if bTotal = false, returns the actual number of lines drawn (which may be less
	// than the number of lines that could be drawn, if there was more text...)
	int VisibleLines(bool bTotal = false) const;
	
	// last and first visible line numbers
	int LastVisibleLine() const;
	int FirstVisibleLine() const;
	
	// characters on screen
	int VisibleColumns() const;
	
	///////////////////////////////////////////////////////////////////////////
	// the parent window can call these to do cut/paste/etc. functions.
	
	// remove selection to the clipboard
	void DoCut();
	
	// copy selection to the clipboard
	void DoCopy();
	
	// paste clipboard. replaces any selection.
	void DoPaste();
	
	// undo the last action
	void DoUndo();
	
	// redo the last undo'd action
	void DoRedo();
	
	// additioinal horizontal spacing
	void SetCharXSpacing(int i);
	
	// additional vertical spacing
	void SetCharYSpacing(int i);
	
	// use your own CColorizer class. 
	// this can actually be changed on-the-fly, if you 
	// need to use a different coloring scheme at will.
	void SetColorizer(CColorizer * pColorizer);
	
	// basic editing stuff
	void SetBackgroundColor(COLORREF clr);
	void SetHighlightColor(COLORREF clr);
	void SetHighlightTextColor(COLORREF clr);
	
	// make this a read-only control
	void SetReadOnly(bool b)      {m_bReadOnly = b;}
	
	void ClearUndoHistory();
	
	// force a recolorization of all text
	void Recolorize();
	
	// handle enter key
	void DoEnter();
	
public:
	virtual ~ColorEditWnd();
	
private:
	// cursor/anchor position 
	void ClipAnchorPosition(int &x, int &y);
	void ClipCursorPosition(int &x, int &y);
	void ClipAnchorPosition(CPoint &p);
	void ClipCursorPosition(CPoint &p);
	
	// warning: these only affect the internal state. they do not update the UI!
	_inline void _SetAnchorPosX(int x)      {m_anchorPos.x = x;}
	_inline void _SetAnchorPosY(int y)      {m_anchorPos.y = y;}
	_inline void _SetAnchorPos(CPoint pt)   {m_anchorPos = pt;}
	_inline void _SetAnchorPos(int x, int y) {m_anchorPos.x = x; m_anchorPos.y = y;}
	
	// warning: these only set the internal data. they do not update the UI!
	_inline void _SetCursorPosX(int x)      {m_cursorPos.x = x;NotifyParent(EN_CURPOSCHANGE,m_cursorPos.x,m_cursorPos.y);}
	_inline void _SetCursorPosY(int y)      {m_cursorPos.y = y;NotifyParent(EN_CURPOSCHANGE,m_cursorPos.x,m_cursorPos.y);}
	_inline void _SetCursorPos(CPoint pt)   {m_cursorPos = pt;NotifyParent(EN_CURPOSCHANGE,m_cursorPos.x,m_cursorPos.y);}
	_inline void _SetCursorPos(int x, int y) {m_cursorPos.x= x;m_cursorPos.y = y;NotifyParent(EN_CURPOSCHANGE,m_cursorPos.x,m_cursorPos.y);}
	
	_inline CPoint   CursorPos() const     {return m_cursorPos;}
	_inline int   CursorPosX() const       {return m_cursorPos.x;}
	_inline int   CursorPosY() const       {return m_cursorPos.y;}
	
	_inline CPoint   AnchorPos() const     {return m_anchorPos;}
	_inline int   AnchorPosX() const       {return m_anchorPos.x;}
	_inline int   AnchorPosY() const       {return m_anchorPos.y;}
	
	// number of lines
	_inline int GetTextSize() const        {return m_text._GetSize();}
	
	// get a single line
	_inline CString GetTextLine(int i) const       {return m_text._GetLine(i);}
	
	// insert/delete
	
	// insert a single line at pos 'i'. 
	void InsertTextLine(CString &line, 
		int i, 
		bool bUpdate=TRUE,      // redraw and recolor. in general, TRUE
		bool bNoUndo = false);  // don't add to undo frame
	
	// insert a string at the current cursor pos
	void InsertText(CString &pString);
	
	// insert a single char at the current cursor pos
	void InsertChar(int pChar, bool pUpdate = TRUE);
	
	// insert a string at the current cursor pos
	void InsertString(CString &pString, bool pUpdate = TRUE);
	
	// insert a single tab (as spaces) at the current cursor pos
	void  InsertTab();
	
	// set a single text line. replaces old contents
	void SetTextLine(CString &line, int i, bool bNoUndo = false, bool pUpdate = TRUE);
	
	// remove the line at 'i'
	void RemoveTextLine(int i, bool bNoUndo = false, bool pUpdate = TRUE);                     
	
	// clear all lines
	void RemoveAllText();                           
	
	void  _ReplaceSelText(const char *pText);
	
	///////////////////////////////////////////////////////////////////////////
	
private:
	CString MakeTab(int iCursorXPos) const;
	
	// for the backspace and delete keys
	void DeleteNextChar();
	void DeletePrevChar();
	
	// selection
	bool IsSelected(int pX,int pY);
	bool Selected();
	void UpdateAnchor(bool pTestShift);
	void RemoveSelected();
	
	// scroll
	void UpdateScrollSizes();
	
	CPoint GetDeviceScrollPosition() const;
	CPoint GetScrollPosition() const;
	
	// output
	CPoint _DrawLine(CDC *pDC, const CString &line, const CScriptText::lineVector &colors, int lineidx, int y);
	void DrawCursor(CDC * pDC, bool pShow);
	void DrawCursor(bool pShow);
	
	void ShiftDisplay(int dx, int dy);
	
	
	// undo stuff
	void StartUndoFrame();
	void EndUndoFrame();
	void ClearUndoStack(undostack &inStack);
	void DoUndoRedo(undostack &inStack, undostack& outStack);
	
	// start/end an undoable action
	void StartAction();
	void EndAction();
	
	// post a windows message to the parent
	void  NotifyParent(UINT msg);
	LRESULT NotifyParent(UINT msg,int code1,int code2);
	
	
	// state
	int m_iCharDX;
	int m_iCharDY;
	int m_iTabSize;
	HCURSOR m_cursor;
	CFont m_font;
	
	// offsets for scrolling
	long			m_iFirstCharacter;
	long			m_iFirstLine;
	
	//caret and cursor postion
	CPoint      m_anchorPos;
	CPoint      m_cursorPos;
	
	// colors
	COLORREF m_backgroundColor;
	COLORREF m_hilightColor;
	COLORREF m_hilightTextColor;
	
	// the text
	CScriptText		m_text;
	
	// sel/drag info
	bool     m_bIsSelected;
	bool     m_bLBDown;
	bool     m_bCaretOn;
	CPoint   m_startPointDrag;
	
	// use accellerators?
	bool     m_bUseKBAccel;
	
	bool     m_bMaintainIndent;
	
	
	// undo/redo state
	
	// current action frame. an action can be composed of one or more sub-actions.
	// for a single keystroke, the undo frame holds one action: the keystroke.
	// for complex actions, like a paste or a cut, the frame will contain all of the 
	// actions required to perform the meta-action.
	CUndoFrame  m_currentUndoFrame;
	
	// holds all of our actions - this might get big. feel free to clear it once in a while.
	undostack   m_undoStack;
	
	// when the user starts undo-ing stuff, the undo's are placed here. 
	// this is cleared when a new undo frame is created, ie. when a new edit action occurs.
	undostack   m_redoStack;
	
	// dialog ID
	UINT  m_ID; 
	
	bool  m_bReadOnly;
	
	HACCEL m_hAccel;
	
public:
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(ColorEditWnd)
public:
	virtual BOOL PreTranslateMessage(MSG* pMsg);
	//}}AFX_VIRTUAL
	
	//{{AFX_MSG(ColorEditWnd)
	afx_msg BOOL OnEraseBkgnd(CDC* pDC);
	afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
	afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
	afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
	afx_msg void OnMouseMove(UINT nFlags, CPoint point);
	afx_msg void OnPaint();
	afx_msg void OnSize(UINT nType, int cx, int cy);
	afx_msg UINT OnGetDlgCode();
	afx_msg void OnVScroll( UINT nSBCode, UINT nPos, CScrollBar* pScrollBar );
	afx_msg void OnHScroll( UINT nSBCode, UINT nPos, CScrollBar* pScrollBar );
	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
	afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
	afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
	afx_msg BOOL OnMouseWheel( UINT nFlags, short zDelta, CPoint pt );
	afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
	afx_msg void OnUpdateCopy(CCmdUI* pCmdUI);
	afx_msg void OnUpdateCut(CCmdUI* pCmdUI);
	afx_msg void OnUpdatePaste(CCmdUI* pCmdUI);
	afx_msg void OnUpdateSelectall(CCmdUI* pCmdUI);
	afx_msg void OnUpdateUndo(CCmdUI* pCmdUI);
	afx_msg void OnUpdateRedo(CCmdUI* pCmdUI);
	afx_msg void OnCopy();
	afx_msg void OnCut();
	afx_msg void OnPaste();
	afx_msg void OnSelectall();
	afx_msg void OnUndo();
	afx_msg void OnRedo();
	afx_msg void OnKillFocus(CWnd* pNewWnd);
	afx_msg void OnSetFocus( CWnd* pOldWnd );
	afx_msg void OnLButtonDblClk( UINT, CPoint );
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
		
		CString m_className;
};


/////////////////////////////////////////////////////////////////////////////
#endif

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

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
Software Developer (Senior) RDV Systems
Israel Israel
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions