📄 umllinesegment.cpp
字号:
/* ==========================================================================
Class : CUMLLineSegment
Author : Johan Rosengren, Abstrakt Mekanik AB
Date : 2004-04-29
Purpose : "CUMLLineSegment" is a "CUMLEntity"-
derived class, representing a line that can be linked
to other "CUMLEntity"-derived objects.
Description : The implementation is based on "CDiagramLine", even though
not derived from it. The class allows two link point,
"LINK_START" and "LINK_END" - the top-left and bottom-right
corners.
The links can be attached to any link point on some
objects, and contains offset values to the top or left
to make it possible to move the segment along with the
linked object.
Usage : Create with "CUMLControlFactory::CreateFromString" or
add an instance to the editor "StartDrawingObject".
========================================================================
Changes:
8/7 2004 Support for the Interface line type added.
5/8 2004 Fixed bug in GetOffset - zoom should *not* be applied.
========================================================================*/
#include "stdafx.h"
#include "UMLLineSegment.h"
#include "UMLEntityContainer.h"
#include "DiagramEditor/DiagramLine.h"
#include "DiagramEditor/Tokenizer.h"
#include "StringHelpers.h"
#include <math.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//////////////////////////////////////////
// LineDDA callbacks from CDiagramLine
//
VOID CALLBACK HitTest( int X, int Y, LPARAM data );
VOID CALLBACK HitTestRect( int X, int Y, LPARAM data );
CUMLLineSegment::CUMLLineSegment()
/* ============================================================
Function : CUMLLineSegment::CUMLLineSegment
Description : Constructor
Access : Public
Return : void
Parameters : none
Usage : Create either through "CUMLControlFactory" or
by calling "new" and adding the pointer to the
editor via "StartDrawingObject"
============================================================*/
{
SetPropertyDialog( &m_dlg, CUMLLinkPropertyDialog::IDD );
SetLinkType( LINK_START, 0 );
SetLinkType( LINK_END, 0 );
SetMinimumSize( CSize( -1, -1 ) );
SetMaximumSize( CSize( -1, -1 ) );
SetType( _T( "uml_line" ) );
SetTitle( _T( "" ) );
SetStyle( 0 );
SetStartLabel( _T( "" ) );
SetEndLabel( _T( "" ) );
SetOffset( LINK_START, 0 );
SetOffset( LINK_END, 0 );
}
CUMLLineSegment::~CUMLLineSegment()
/* ============================================================
Function : CUMLLineSegment::~CUMLLineSegment
Description : Destructor
Access : Public
Return : void
Parameters : none
Usage : Note that objects will normally be deleted by
the container.
============================================================*/
{
if( m_dlg.m_hWnd )
m_dlg.DestroyWindow();
}
CDiagramEntity* CUMLLineSegment::Clone()
/* ============================================================
Function : CUMLLineSegment::Clone
Description : Clone this object to a new object.
Access : Public
Return : CDiagramEntity* - The new object.
Parameters : none
Usage : Call to create a clone of the object. The
caller will have to delete the object.
============================================================*/
{
CUMLLineSegment* obj = new CUMLLineSegment;
obj->Copy( this );
return obj;
}
void CUMLLineSegment::Draw( CDC* dc, CRect rect )
/* ============================================================
Function : CUMLLineSegment::Draw
Description : Draws the object.
Access : Public
Return : void
Parameters : CDC* dc - The "CDC" to draw to.
CRect rect - The real rectangle of the
object.
Usage : The function should clean up all selected
objects. Note that the "CDC" is a memory "CDC",
so creating a memory "CDC" in this function
will probably not speed up the function.
============================================================*/
{
int mode = dc->SetBkMode( TRANSPARENT );
if( !( GetStyle() & STYLE_INVISIBLE ) )
{
CPen pen;
if( GetStyle() & STYLE_DASHED )
pen.CreatePen( PS_DOT, 0, RGB( 0, 0, 0 ) );
else
pen.CreatePen( PS_SOLID, 0, RGB( 0, 0, 0 ) );
CPen* oldpen = dc->SelectObject( &pen );
// Draw line
dc->MoveTo( rect.TopLeft() );
dc->LineTo( rect.BottomRight() );
dc->SelectObject( oldpen );
}
dc->SelectStockObject( BLACK_PEN );
dc->SelectStockObject( BLACK_BRUSH );
int cut = round( static_cast< double >( GetMarkerSize().cx ) * GetZoom() / 2 );
int cy = round( 14.0 * GetZoom() );
CFont font;
font.CreateFont( -round( 12.0 * GetZoom() ), 0,0,0,FW_NORMAL,0,0,0,0,0,0,0,0, GetFont() );
CFont* oldfont = dc->SelectObject( &font );
/////////////////////////////////////////////////////////////
// Draw title
CString str = GetTitle();
if( str.GetLength() )
{
CRect rectTemp( rect );
rectTemp.NormalizeRect();
CRect r( rect.right - cut, rect.top, rect.right - ( rectTemp.Width() + cut ), rect.bottom );
if( IsHorizontal() )
{
CRect r( rect.left, rect.top - ( cy + cut ), rect.right, rect.bottom );
r.NormalizeRect();
dc->DrawText( str, r, DT_NOPREFIX | DT_SINGLELINE | DT_CENTER );
}
else
{
CRect r( rect.right - ( dc->GetTextExtent( str ).cx + cut * 2 ), rect.top, rect.right - cut, rect.bottom );
r.NormalizeRect();
dc->DrawText( str, r, DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER | DT_RIGHT );
}
}
/////////////////////////////////////////////////////////////
// Draw labels
str = GetStartLabel();
if( str.GetLength() )
{
CRect rectTemp( rect );
if( IsHorizontal() )
{
rectTemp.bottom = rectTemp.top - cut;
rectTemp.top -= cy + cut;
if( rectTemp.left < rectTemp.right )
{
rectTemp.left += cut;
rectTemp.right -= cut;
dc->DrawText( str, rectTemp, DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER | DT_LEFT );
}
else
{
int temp = rectTemp.left;
rectTemp.left = rectTemp.right + cut;
rectTemp.right = temp - cut;
dc->DrawText( str, rectTemp, DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER | DT_RIGHT );
}
}
else
{
rectTemp.left -= dc->GetTextExtent( str ).cx + 2 * cut;
rectTemp.right -= cut;
if( rectTemp.top < rectTemp.bottom )
rectTemp.bottom = rectTemp.top + cy;
else
{
rectTemp.top -= cy;
rectTemp.bottom = rectTemp.top + cy;
}
dc->DrawText( str, rectTemp, DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER | DT_RIGHT );
}
}
str = GetSecondaryStartLabel();
if( str.GetLength() )
{
CRect rectTemp( rect );
if( IsHorizontal() )
{
rectTemp.bottom += cy + cut;
rectTemp.top += cut;
if( rectTemp.left < rectTemp.right )
{
rectTemp.left += cut;
rectTemp.right -= cut;
dc->DrawText( str, rectTemp, DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER | DT_LEFT );
}
else
{
int temp = rectTemp.left;
rectTemp.left = rectTemp.right + cut;
rectTemp.right = temp - cut;
dc->DrawText( str, rectTemp, DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER | DT_RIGHT );
}
}
else
{
rectTemp.right += dc->GetTextExtent( str ).cx + 2 * cut;
rectTemp.left += cut;
if( rectTemp.top < rectTemp.bottom )
rectTemp.bottom = rectTemp.top + cy;
else
{
rectTemp.top -= cy;
rectTemp.bottom = rectTemp.top + cy;
}
dc->DrawText( str, rectTemp, DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER | DT_RIGHT );
}
}
str = GetEndLabel();
if( str.GetLength() )
{
CRect rectTemp( rect );
if( IsHorizontal() )
{
rectTemp.bottom = rectTemp.top - cut;
rectTemp.top -= cy + cut;
if( rectTemp.left < rectTemp.right )
{
rectTemp.left += cut;
rectTemp.right -= cut;
dc->DrawText( str, rectTemp, DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER | DT_RIGHT );
}
else
{
int temp = rectTemp.left;
rectTemp.left = rectTemp.right + cut;
rectTemp.right = temp - cut;
dc->DrawText( str, rectTemp, DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER | DT_LEFT );
}
}
else
{
rectTemp.left -= dc->GetTextExtent( str ).cx + 2 * cut;
rectTemp.right -= cut;
if( rectTemp.top < rectTemp.bottom )
rectTemp.top = rectTemp.bottom - cy;
else
{
rectTemp.top = rectTemp.bottom;
rectTemp.bottom = rectTemp.top + cy;
}
dc->DrawText( str, rectTemp, DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER | DT_RIGHT );
}
}
str = GetSecondaryEndLabel();
if( str.GetLength() )
{
CRect rectTemp( rect );
if( IsHorizontal() )
{
rectTemp.bottom += cy + cut;
rectTemp.top += cut;
if( rectTemp.left < rectTemp.right )
{
rectTemp.left += cut;
rectTemp.right -= cut;
dc->DrawText( str, rectTemp, DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER | DT_RIGHT );
}
else
{
int temp = rectTemp.left;
rectTemp.left = rectTemp.right + cut;
rectTemp.right = temp - cut;
dc->DrawText( str, rectTemp, DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER | DT_LEFT );
}
}
else
{
rectTemp.right += dc->GetTextExtent( str ).cx + 2 * cut;
rectTemp.left += cut;
if( rectTemp.top < rectTemp.bottom )
rectTemp.top = rectTemp.bottom - cy;
else
{
rectTemp.top = rectTemp.bottom;
rectTemp.bottom = rectTemp.top + cy;
}
dc->DrawText( str, rectTemp, DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER | DT_RIGHT );
}
}
/////////////////////////////////////////////////////////////
// Draw markers
int hgt = GetMarkerSize().cy / 2;
if( GetStyle() & STYLE_FILLED_DIAMOND )
{
CRect diamond;
double x2 = GetLeft();
double x1 = GetRight();
double y2 = GetTop();
double y1 = GetBottom();
if( !( GetLinkType( LINK_END ) & LINK_ALL ) &&
( GetLinkType( LINK_START ) & LINK_ALL ) )
{
x2 = GetRight();
x1 = GetLeft();
y2 = GetBottom();
y1 = GetTop();
}
if( IsHorizontal() )
{
diamond.left = round( x1 * GetZoom() );
diamond.top = round( ( y1 - hgt ) * GetZoom() );
diamond.bottom = diamond.top + round( hgt * 2 * GetZoom() );
if( x1 < x2 )
diamond.right = diamond.left + round( hgt * 4 * GetZoom() );
else
diamond.right = diamond.left - round( hgt * 4 * GetZoom() );
diamond.NormalizeRect();
}
else
{
diamond.top = round( y1 * GetZoom() );
diamond.left = round( ( x1 - hgt ) * GetZoom() );
diamond.right = diamond.left + round( hgt * 2 * GetZoom() );
if( y1 < y2 )
diamond.bottom = diamond.top + round( hgt * 4 * GetZoom() );
else
diamond.bottom = diamond.top - round( hgt * 4 * GetZoom() );
rect.NormalizeRect();
}
DrawDiamond( dc, diamond );
}
if( GetStyle() & STYLE_CIRCLECROSS )
{
CSize marker( 16, 16 );
CPoint pos = GetStyleMarkerRect( LINK_END, marker );
CRect circ( round( static_cast< double >( pos.x ) * GetZoom() ), round( static_cast< double >( pos.y ) * GetZoom() ), round( static_cast< double >( pos.x + marker.cx ) * GetZoom() ), round( static_cast< double >( pos.y + marker.cy ) * GetZoom() ) );
dc->SelectStockObject( BLACK_PEN );
dc->SelectStockObject( WHITE_BRUSH );
dc->Ellipse( &circ );
dc->MoveTo( circ.left + circ.Width() / 2, circ.top );
dc->LineTo( circ.left + circ.Width() / 2, circ.bottom );
dc->MoveTo( circ.left, circ.top + circ.Height() / 2 );
dc->LineTo( circ.right, circ.top + circ.Height() / 2 );
}
if( GetStyle() & STYLE_ARROWHEAD )
DrawInheritanceArrow( dc );
if( GetStyle() & STYLE_FILLED_ARROWHEAD )
DrawDirectionArrow( dc );
/////////////////////////////////////////////////////////////
// Cleaning up
dc->SetBkMode( mode );
dc->SelectObject( oldfont );
dc->SelectStockObject( WHITE_BRUSH );
}
CDiagramEntity* CUMLLineSegment::CreateFromString( const CString& str )
/* ============================================================
Function : CUMLLineSegment::CreateFromString
Description : Static factory function that creates and
returns an instance of this class if "str"
is a valid representation.
Access : Public
Return : CDiagramEntity* - The object, or "NULL"
if "str" is not a
representation of
this type.
Parameters : const CString& str - The string to create
from.
Usage : Can be used as a factory for text file loads.
Each object type should have its own
version - the default one is a model
implementation.
============================================================*/
{
CUMLLineSegment* obj = new CUMLLineSegment;
if(!obj->FromString( str ) )
{
delete obj;
obj = NULL;
}
return obj;
}
int CUMLLineSegment::GetHitCode( CPoint point ) const
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -