⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 flowcharteditor.cpp

📁 大家用过UML的流程图设计器吧
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/* ==========================================================================
	CFlowchartEditor

	Author :		Johan Rosengren, Abstrakt Mekanik AB

	Date :			2004-05-01

	Purpose :		CFlowchartEditor is a flowchart editor, demonstrating 
					several concepts of CDiagramEditor:	

					1.	Linking objects using a CDiagramEntityContainer-
						derived class to manage data
					2.	Putting CDiagramEditor in a MDI-application, using 
						a shared CDiagramClipboard-derived clipboard handler.
					3.	Exporting the diagram to an enhanced metafile that 
						can be pasted into - for example - Word.

	Description :	CFlowcharEditor handles several messages and overrides 
					drawing to manage links. Links are implemented as a 
					special class, stored in a separate array in 
					CFlowchartEntityContainer. Object drawing in 
					CFlowchartEditor also draws the links. 

					The objects derived from CFlowchartEntity has link 
					points. Two selected and unlinked objects with free 
					link points at appropriate position can be linked. If 
					they are linked, a line is automatically drawn between 
					the objects, with an arrow head representing the 
					direction (which can be flipped).

					The link can have a label, that is, a text describing 
					the link.

					When objects are moved, other objects linked to the 
					moved ones might also be moved - depending on the links. 
					For example, if two objects are linked horizontally and 
					one is moved up or down, the linked object will also be 
					moved. 

					A special type of object is the linkable line. Linkable 
					lines are lines that can be linked to other objects, 
					even lines. They can be used to represent more complex 
					flows, such as several links converging on a single spot. 
					Lines will also be moved as other objects, but worth to 
					notice is that they will not be resized, they will keep 
					their original length and might therefore trigger 
					movements far from the current one. Linked lines can 
					only be drawn either vertically or horizontally, that is, 
					no slant is allowed - this is enforced by the editor 
					rather than the line class.

	Usage :			CFlowchartEditor should be instantiated in the same way 
					as a CDiagramEditor. The two public member functions 
					CanLink and IsLinked can be used for command enablers 
					for the commands OnLink, OnUnlink, OnLinkDirection and 
					OnLinkProperties. The commands link, unlink, reverse 
					direction of the link and sets/edit the link label 
					respectively.

					The package uses RTTI (run time type information) to 
					identify object types, using dynamic_cast, so the 
					project must enable this feature.

   ========================================================================*/

#include "stdafx.h"
#include "FlowchartEditor.h"
#include "FlowchartEntityContainer.h"
#include "FlowchartMenu.h"
#include "FlowchartLinkPropertiesDialog.h"
#include "FlowchartLinkableLineSegment.h"

#include <math.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CFlowchartEditor

CFlowchartEditor::CFlowchartEditor()
/* ============================================================
	Function :		CFlowchartEditor::CFlowchartEditor
	Description :	constructor
					
	Return :		void
	Parameters :	none

	Usage :			

   ============================================================*/
{

	SetBackgroundColor( RGB( 250, 250, 230 ) );
	SetSnapToGrid( TRUE );
	SetRestraints( RESTRAINT_VIRTUAL );
	SetPopupMenu( new CFlowchartMenu );

}

CFlowchartEditor::~CFlowchartEditor()
/* ============================================================
	Function :		CFlowchartEditor::~CFlowchartEditor
	Description :	destructor
					
	Return :		void
	Parameters :	none

	Usage :			

   ============================================================*/
{
}

BEGIN_MESSAGE_MAP(CFlowchartEditor, CDiagramEditor)
	ON_COMMAND(IDM_FLOWCHARTEDITOR_LINK, OnLink)
	ON_COMMAND(IDM_FLOWCHARTEDITOR_UNLINK, OnUnlink)
	ON_COMMAND(IDM_FLOWCHARTEDITOR_LINK_DIRECTION, OnLinkDirection)
	ON_COMMAND(IDM_FLOWCHARTEDITOR_LINK_PROPERTIES, OnLinkProperties)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CFlowchartEditor overrides

void CFlowchartEditor::DrawGrid( CDC* dc, CRect /*rect*/, double zoom ) const
/* ============================================================
	Function :		CFlowchartEditor::DrawGrid
	Description :	Draws the editor grid. We override this to 
					draw the grid as a series of dots.
					
	Return :		void
	Parameters :	CDC* dc		-	CDC to draw to
					CRect		-	Complete rect
					double zoom	-	Current zoom level
					
	Usage :			Do not call directly.

   ============================================================*/
{

	COLORREF gridcol = GetGridColor();

	dc->SelectStockObject( BLACK_PEN );

	int stepx = GetVirtualSize().cx / GetGridSize().cx;
	int stepy = GetVirtualSize().cy / GetGridSize().cy;

	for( int x = 0 ; x <= stepx ; x++ )
		for( int y = 0; y <= stepy ; y++ )
			dc->SetPixel( round( ( double ) ( GetGridSize().cx * x ) * zoom ), round( ( double ) ( GetGridSize().cy * y ) * zoom ), gridcol );

}

void CFlowchartEditor::DrawObjects( CDC* dc, double zoom ) const
/* ============================================================
	Function :		CFlowchartEditor::DrawObjects
	Description :	Draws the object
					
	Return :		void
	Parameters :	CDC* dc		-	CDC to draw to
					double zoom	-	Zoom level (use this value 
									instead of GetZoom())
					
	Usage :			Overridden to draw links.

   ============================================================*/
{

	CFlowchartEntityContainer* objs = dynamic_cast< CFlowchartEntityContainer * >( GetDiagramEntityContainer() );
	if( objs )
	{
		CFont font;
		font.CreateFont( -round( 12.0 * zoom ), 0,0,0,FW_NORMAL,0,0,0,0,0,0,0,0, _T( "Courier New" ) );

		int count = GetObjectCount();

		int max = objs->GetLinks();
		int seg = round( ( double ) GetMarkerSize().cx * zoom / 2 );
		POINT pts[ 3 ];

		for( int i = 0 ; i < count ; i++ )
		{

			CDiagramEntity* main = static_cast< CDiagramEntity* >( objs->GetAt( i ) );
			CFlowchartEntity* obj = dynamic_cast< CFlowchartEntity* >( objs->GetAt( i ) );
			if( obj )
			{
				for( int t = 0 ; t < max ; t++ )
				{
					CFlowchartLink* link = objs->GetLinkAt( t );
					if( link && link->from == obj->GetName() )
					{

						dc->SelectStockObject( BLACK_PEN );
						dc->SelectStockObject( BLACK_BRUSH );

						CFlowchartEntity* to = GetNamedObject( link->to );

						BOOL drawArrow = TRUE;
						CPoint start;
						CPoint end;
						start = obj->GetLinkPosition( link->fromtype );
						end = to->GetLinkPosition( link->totype );

						start.x = round( ( double ) start.x * zoom );
						start.y = round( ( double ) start.y * zoom );
						end.x = round( ( double ) end.x * zoom );
						end.y = round( ( double ) end.y * zoom );

						switch( link->fromtype )
						{
							case LINK_RIGHT:
								pts[ 1 ].x = end.x - seg * 2;
								pts[ 1 ].y = end.y - seg;
								pts[ 2 ].x = end.x - seg * 2;
								pts[ 2 ].y = end.y + seg;
							break;

							case LINK_LEFT:
								pts[ 1 ].x = end.x + seg * 2;
								pts[ 1 ].y = end.y - seg;
								pts[ 2 ].x = end.x + seg * 2;
								pts[ 2 ].y = end.y + seg;
							break;

							case LINK_TOP:
								pts[ 1 ].x = end.x - seg;
								pts[ 1 ].y = end.y + seg * 2;
								pts[ 2 ].x = end.x + seg;
								pts[ 2 ].y = end.y + seg * 2;
							break;

							case LINK_BOTTOM:
								pts[ 1 ].x = end.x - seg;
								pts[ 1 ].y = end.y - seg * 2;
								pts[ 2 ].x = end.x + seg;
								pts[ 2 ].y = end.y - seg * 2;

							break;

							default:
							{
								switch( link->totype )
								{
									case LINK_RIGHT:
										pts[ 1 ].x = end.x + seg * 2;
										pts[ 1 ].y = end.y - seg;
										pts[ 2 ].x = end.x + seg * 2;
										pts[ 2 ].y = end.y + seg;
									break;

									case LINK_LEFT:
										pts[ 1 ].x = end.x - seg * 2;
										pts[ 1 ].y = end.y - seg;
										pts[ 2 ].x = end.x - seg * 2;
										pts[ 2 ].y = end.y + seg;
									break;

									case LINK_TOP:
										pts[ 1 ].x = end.x - seg;
										pts[ 1 ].y = end.y - seg * 2;
										pts[ 2 ].x = end.x + seg;
										pts[ 2 ].y = end.y - seg * 2;
									break;

									case LINK_BOTTOM:
										pts[ 1 ].x = end.x - seg;
										pts[ 1 ].y = end.y + seg * 2;
										pts[ 2 ].x = end.x + seg;
										pts[ 2 ].y = end.y + seg * 2;
									break;

									default:
										drawArrow = FALSE;
									break;
								}
							}
							break;
						}

						dc->MoveTo( start );
						dc->LineTo( end );

						pts[ 0 ].x = end.x;
						pts[ 0 ].y = end.y;

						if( drawArrow )
							dc->Polygon( pts, 3 );

						CString str = link->title;
						if( str.GetLength() )
						{
							dc->SelectObject( &font );
							int mode = dc->SetBkMode( TRANSPARENT );

							CRect rect( start, end );
							rect.NormalizeRect();
							int cy = round( 14.0 * zoom );
							int cut = round( ( double ) GetMarkerSize().cx * zoom / 2 );
							CRect r( rect.right - cut, rect.top, rect.right - ( rect.Width() + cut ), rect.bottom );
							if(rect.top==rect.bottom)
							{
								CRect r( rect.left, rect.top - ( cy + cut ), rect.right, rect.bottom );
								r.NormalizeRect();
								dc->DrawText( str, r, DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER | DT_CENTER );
							}
							else
							{
								CRect r( rect.right - cut, rect.top, rect.right - ( cy * str.GetLength() + cut ), rect.bottom );
								r.NormalizeRect();
								dc->DrawText( str, r, DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER | DT_RIGHT );
							}

							dc->SetBkMode( mode );
							dc->SelectStockObject( DEFAULT_GUI_FONT );

						}
					}
				}
			}

			main->DrawObject( dc, zoom );
		}
	}

}

void CFlowchartEditor::SaveObjects( CStringArray& stra )
/* ============================================================
	Function :		CFlowchartEditor::SaveObjects
	Description :	Saves all the objects to a CStringArray.
					
	Return :		void
	Parameters :	CStringArray& stra	-	CStringArray to 
											save to.
					
	Usage :			Overridden to save the links as well.

   ============================================================*/
{

	CDiagramEditor::SaveObjects( stra );
	CFlowchartEntityContainer* objs = dynamic_cast< CFlowchartEntityContainer * >( GetDiagramEntityContainer() );
	if( objs )
	{
		int max = objs->GetLinks();
		for( int t = 0 ; t < max ; t++ )
		{
			CFlowchartLink* link = objs->GetLinkAt( t );
			stra.Add( link->GetString() );
		}
	}

}

/////////////////////////////////////////////////////////////////////////////
// CFlowchartEditor message handlers

void CFlowchartEditor::OnMouseMove( UINT nFlags, CPoint point )
/* ============================================================
	Function :		CFlowchartEditor::OnMouseMove
	Description :	Handler for WM_MOUSEMOVE. We add handling 
					to close screen redraws as we are moving 
					lots of stuff (all the attached objects in 
					addition to the primarily moved). We also 
					do secondary movements here - that is, 
					objects linked to the one(s) being moved 
					must be moved as well, even if they are 
					not selected.
					
	Return :		void
	Parameters :	UINT nFlags		-	Not used
					CPoint point	-	Not used
					
	Usage :			Called from MFC

   ============================================================*/
{
	if( ( GetInteractMode() == MODE_MOVING ) || ( GetInteractMode() == MODE_RESIZING && GetSelectCount() == 1 ) )
		SetRedraw( FALSE );

	CDiagramEditor::OnMouseMove( nFlags, point );

	if( GetInteractMode() == MODE_RESIZING )
	{
		if( GetSelectCount() == 1 )
		{
			CFlowchartLinkableLineSegment* obj = dynamic_cast< CFlowchartLinkableLineSegment* >( GetSelectedObject() );
			if( obj )
			{
				if( obj->GetLeft() != obj->GetRight() && obj->GetTop() != obj->GetBottom() )
				{
					if( fabs( obj->GetLeft() - obj->GetRight() ) > fabs( obj->GetTop() - obj->GetBottom() ) )
						obj->SetBottom( obj->GetTop() );
					else
						obj->SetRight( obj->GetLeft() );
				}
			}
		}

	}

	if( GetInteractMode() == MODE_MOVING || GetInteractMode() == MODE_RESIZING)
	{
		ModifyLinkedPositions();
		SetRedraw( TRUE );
		RedrawWindow();
	}

}

void CFlowchartEditor::OnKeyDown( UINT nChar, UINT nRepCnt, UINT nFlags ) 
/* ============================================================
	Function :		CFlowchartEditor::OnKeyDown
	Description :	Handles the WM_KEYDOWN-message. We 
					override this as objects might be moved and
					we will have to move unlinked objects as
					well.
					

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -