1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     wxLineShape 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  13 #pragma implementation "lines.h" 
  16 // For compilers that support precompilation, includes "wx.h". 
  17 #include <wx/wxprec.h> 
  28 #include <wx/wxexpr.h> 
  49 IMPLEMENT_DYNAMIC_CLASS(wxLineShape
, wxShape
) 
  51 wxLineShape::wxLineShape() 
  53   m_sensitivity 
= OP_CLICK_LEFT 
| OP_CLICK_RIGHT
; 
  58   m_actualTextWidth = 0.0; 
  59   m_actualTextHeight = 0.0; 
  64   m_arrowSpacing 
= 5.0; // For the moment, don't bother saving this to file. 
  65   m_ignoreArrowOffsets 
= FALSE
; 
  67   m_maintainStraightLines 
= FALSE
; 
  71   m_lineControlPoints 
= NULL
; 
  73   // Clear any existing regions (created in an earlier constructor) 
  74   // and make the three line regions. 
  76   wxShapeRegion 
*newRegion 
= new wxShapeRegion
; 
  77   newRegion
->SetName("Middle"); 
  78   newRegion
->SetSize(150, 50); 
  79   m_regions
.Append((wxObject 
*)newRegion
); 
  81   newRegion 
= new wxShapeRegion
; 
  82   newRegion
->SetName("Start"); 
  83   newRegion
->SetSize(150, 50); 
  84   m_regions
.Append((wxObject 
*)newRegion
);   
  86   newRegion 
= new wxShapeRegion
; 
  87   newRegion
->SetName("End"); 
  88   newRegion
->SetSize(150, 50); 
  89   m_regions
.Append((wxObject 
*)newRegion
); 
  91   for (int i 
= 0; i 
< 3; i
++) 
  92     m_labelObjects
[i
] = NULL
; 
  95 wxLineShape::~wxLineShape() 
  97   if (m_lineControlPoints
) 
  99     ClearPointList(*m_lineControlPoints
); 
 100     delete m_lineControlPoints
; 
 102   for (int i 
= 0; i 
< 3; i
++) 
 104     if (m_labelObjects
[i
]) 
 106       m_labelObjects
[i
]->Select(FALSE
); 
 107       m_labelObjects
[i
]->RemoveFromCanvas(m_canvas
); 
 108       delete m_labelObjects
[i
]; 
 109       m_labelObjects
[i
] = NULL
; 
 114 void wxLineShape::MakeLineControlPoints(int n
) 
 116   if (m_lineControlPoints
) 
 118     ClearPointList(*m_lineControlPoints
); 
 119     delete m_lineControlPoints
; 
 121   m_lineControlPoints 
= new wxList
; 
 124   for (i 
= 0; i 
< n
; i
++) 
 126     wxRealPoint 
*point 
= new wxRealPoint(-999, -999); 
 127     m_lineControlPoints
->Append((wxObject
*) point
); 
 131 wxNode 
*wxLineShape::InsertLineControlPoint(wxDC
* dc
) 
 136   wxNode 
*last 
= m_lineControlPoints
->Last(); 
 137   wxNode 
*second_last 
= last
->Previous(); 
 138   wxRealPoint 
*last_point 
= (wxRealPoint 
*)last
->Data(); 
 139   wxRealPoint 
*second_last_point 
= (wxRealPoint 
*)second_last
->Data(); 
 141   // Choose a point half way between the last and penultimate points 
 142   float line_x 
= ((last_point
->x 
+ second_last_point
->x
)/2); 
 143   float line_y 
= ((last_point
->y 
+ second_last_point
->y
)/2); 
 145   wxRealPoint 
*point 
= new wxRealPoint(line_x
, line_y
); 
 146   wxNode 
*node 
= m_lineControlPoints
->Insert(last
, (wxObject
*) point
); 
 150 bool wxLineShape::DeleteLineControlPoint() 
 152   if (m_lineControlPoints
->Number() < 3) 
 155   wxNode 
*last 
= m_lineControlPoints
->Last(); 
 156   wxNode 
*second_last 
= last
->Previous(); 
 158   wxRealPoint 
*second_last_point 
= (wxRealPoint 
*)second_last
->Data(); 
 159   delete second_last_point
; 
 165 void wxLineShape::Initialise() 
 167   if (m_lineControlPoints
) 
 169     // Just move the first and last control points 
 170     wxNode 
*first 
= m_lineControlPoints
->First(); 
 171     wxRealPoint 
*first_point 
= (wxRealPoint 
*)first
->Data(); 
 173     wxNode 
*last 
= m_lineControlPoints
->Last(); 
 174     wxRealPoint 
*last_point 
= (wxRealPoint 
*)last
->Data(); 
 176     // If any of the line points are at -999, we must 
 177     // initialize them by placing them half way between the first 
 179     wxNode 
*node 
= first
->Next(); 
 182       wxRealPoint 
*point 
= (wxRealPoint 
*)node
->Data(); 
 183       if (point
->x 
== -999) 
 185         float x1
, y1
, x2
, y2
; 
 186         if (first_point
->x 
< last_point
->x
) 
 187           { x1 
= first_point
->x
; x2 
= last_point
->x
; } 
 189           { x2 
= first_point
->x
; x1 
= last_point
->x
; } 
 191         if (first_point
->y 
< last_point
->y
) 
 192           { y1 
= first_point
->y
; y2 
= last_point
->y
; } 
 194           { y2 
= first_point
->y
; y1 
= last_point
->y
; } 
 196         point
->x 
= ((x2 
- x1
)/2 + x1
); 
 197         point
->y 
= ((y2 
- y1
)/2 + y1
); 
 204 // Format a text string according to the region size, adding 
 205 // strings with positions to region text list 
 206 void wxLineShape::FormatText(wxDC
& dc
, const wxString
& s
, int i
) 
 211   if (m_regions
.Number() < 1) 
 213   wxNode 
*node 
= m_regions
.Nth(i
); 
 217   wxShapeRegion 
*region 
= (wxShapeRegion 
*)node
->Data(); 
 219   dc
.SetFont(region
->GetFont()); 
 221   region
->GetSize(&w
, &h
); 
 222   // Initialize the size if zero 
 223   if (((w 
== 0) || (h 
== 0)) && (strlen(s
) > 0)) 
 226     region
->SetSize(w
, h
); 
 229   wxList 
*string_list 
= ::FormatText(dc
, s
, (w
-5), (h
-5), region
->GetFormatMode()); 
 230   node 
= string_list
->First(); 
 233     char *s 
= (char *)node
->Data(); 
 234     wxShapeTextLine 
*line 
= new wxShapeTextLine(0.0, 0.0, s
); 
 235     region
->GetFormattedText().Append((wxObject 
*)line
); 
 237     node 
= string_list
->First(); 
 242   if (region
->GetFormatMode() & FORMAT_SIZE_TO_CONTENTS
) 
 244     GetCentredTextExtent(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, w
, h
, &actualW
, &actualH
); 
 245     if ((actualW 
!= w 
) || (actualH 
!= h
)) 
 248       GetLabelPosition(i
, &xx
, &yy
); 
 249       EraseRegion(dc
, region
, xx
, yy
); 
 250       if (m_labelObjects
[i
]) 
 252         m_labelObjects
[i
]->Select(FALSE
); 
 253         m_labelObjects
[i
]->Erase(dc
); 
 254         m_labelObjects
[i
]->SetSize(actualW
, actualH
); 
 257       region
->SetSize(actualW
, actualH
); 
 259       if (m_labelObjects
[i
]) 
 261         m_labelObjects
[i
]->Select(TRUE
, & dc
); 
 262         m_labelObjects
[i
]->Draw(dc
); 
 266   CentreText(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, actualW
, actualH
, region
->GetFormatMode()); 
 270 void wxLineShape::DrawRegion(wxDC
& dc
, wxShapeRegion 
*region
, float x
, float y
) 
 272   if (GetDisableLabel()) 
 277   region
->GetSize(&w
, &h
); 
 279   // Get offset from x, y 
 280   region
->GetPosition(&xx
, &yy
); 
 285   // First, clear a rectangle for the text IF there is any 
 286   if (region
->GetFormattedText().Number() > 0) 
 288       dc
.SetPen(white_background_pen
); 
 289       dc
.SetBrush(white_background_brush
); 
 292       if (region
->GetFont()) dc
.SetFont(region
->GetFont()); 
 294       dc
.DrawRectangle((float)(xp 
- w
/2.0), (float)(yp 
- h
/2.0), (float)w
, (float)h
); 
 296       if (m_pen
) dc
.SetPen(m_pen
); 
 297       dc
.SetTextForeground(* region
->GetActualColourObject()); 
 300       dc
.SetTextBackground(white_background_brush
->GetColour()); 
 303       DrawFormattedText(dc
, &(region
->GetFormattedText()), xp
, yp
, w
, h
, region
->GetFormatMode()); 
 307 void wxLineShape::EraseRegion(wxDC
& dc
, wxShapeRegion 
*region
, float x
, float y
) 
 309   if (GetDisableLabel()) 
 314   region
->GetSize(&w
, &h
); 
 316   // Get offset from x, y 
 317   region
->GetPosition(&xx
, &yy
); 
 322   if (region
->GetFormattedText().Number() > 0) 
 324       dc
.SetPen(white_background_pen
); 
 325       dc
.SetBrush(white_background_brush
); 
 327       dc
.DrawRectangle((float)(xp 
- w
/2.0), (float)(yp 
- h
/2.0), (float)w
, (float)h
); 
 331 // Get the reference point for a label. Region x and y 
 332 // are offsets from this. 
 333 // position is 0, 1, 2 
 334 void wxLineShape::GetLabelPosition(int position
, float *x
, float *y
) 
 340       // Want to take the middle section for the label 
 341       int n 
= m_lineControlPoints
->Number(); 
 342       int half_way 
= (int)(n
/2); 
 344       // Find middle of this line 
 345       wxNode 
*node 
= m_lineControlPoints
->Nth(half_way 
- 1); 
 346       wxRealPoint 
*point 
= (wxRealPoint 
*)node
->Data(); 
 347       wxNode 
*next_node 
= node
->Next(); 
 348       wxRealPoint 
*next_point 
= (wxRealPoint 
*)next_node
->Data(); 
 350       float dx 
= (next_point
->x 
- point
->x
); 
 351       float dy 
= (next_point
->y 
- point
->y
); 
 352       *x 
= (float)(point
->x 
+ dx
/2.0); 
 353       *y 
= (float)(point
->y 
+ dy
/2.0); 
 358       wxNode 
*node 
= m_lineControlPoints
->First(); 
 359       *x 
= ((wxRealPoint 
*)node
->Data())->x
; 
 360       *y 
= ((wxRealPoint 
*)node
->Data())->y
; 
 365       wxNode 
*node 
= m_lineControlPoints
->Last(); 
 366       *x 
= ((wxRealPoint 
*)node
->Data())->x
; 
 367       *y 
= ((wxRealPoint 
*)node
->Data())->y
; 
 376  * Find whether line is supposed to be vertical or horizontal and 
 380 void GraphicsStraightenLine(wxRealPoint 
*point1
, wxRealPoint 
*point2
) 
 382   float dx 
= point2
->x 
- point1
->x
; 
 383   float dy 
= point2
->y 
- point1
->y
; 
 387   else if (fabs(dy
/dx
) > 1.0) 
 389     point2
->x 
= point1
->x
; 
 391   else point2
->y 
= point1
->y
; 
 394 void wxLineShape::Straighten(wxDC
& dc
) 
 396   if (!m_lineControlPoints 
|| m_lineControlPoints
->Number() < 3) 
 401   wxNode 
*first_point_node 
= m_lineControlPoints
->First(); 
 402   wxNode 
*last_point_node 
= m_lineControlPoints
->Last(); 
 403   wxNode 
*second_last_point_node 
= last_point_node
->Previous(); 
 405   wxRealPoint 
*last_point 
= (wxRealPoint 
*)last_point_node
->Data(); 
 406   wxRealPoint 
*second_last_point 
= (wxRealPoint 
*)second_last_point_node
->Data(); 
 408   GraphicsStraightenLine(last_point
, second_last_point
); 
 410   wxNode 
*node 
= first_point_node
; 
 411   while (node 
&& (node 
!= second_last_point_node
)) 
 413     wxRealPoint 
*point 
= (wxRealPoint 
*)node
->Data(); 
 414     wxRealPoint 
*next_point 
= (wxRealPoint 
*)(node
->Next()->Data()); 
 416     GraphicsStraightenLine(point
, next_point
); 
 424 void wxLineShape::Unlink() 
 427     m_to
->GetLines().DeleteObject(this); 
 429     m_from
->GetLines().DeleteObject(this); 
 434 void wxLineShape::SetEnds(float x1
, float y1
, float x2
, float y2
) 
 437   wxNode 
*first_point_node 
= m_lineControlPoints
->First(); 
 438   wxNode 
*last_point_node 
= m_lineControlPoints
->Last(); 
 439   wxRealPoint 
*first_point 
= (wxRealPoint 
*)first_point_node
->Data(); 
 440   wxRealPoint 
*last_point 
= (wxRealPoint 
*)last_point_node
->Data(); 
 447   m_xpos 
= (float)((x1 
+ x2
)/2.0); 
 448   m_ypos 
= (float)((y1 
+ y2
)/2.0); 
 451 // Get absolute positions of ends 
 452 void wxLineShape::GetEnds(float *x1
, float *y1
, float *x2
, float *y2
) 
 454   wxNode 
*first_point_node 
= m_lineControlPoints
->First(); 
 455   wxNode 
*last_point_node 
= m_lineControlPoints
->Last(); 
 456   wxRealPoint 
*first_point 
= (wxRealPoint 
*)first_point_node
->Data(); 
 457   wxRealPoint 
*last_point 
= (wxRealPoint 
*)last_point_node
->Data(); 
 459   *x1 
= first_point
->x
; *y1 
= first_point
->y
; 
 460   *x2 
= last_point
->x
; *y2 
= last_point
->y
; 
 463 void wxLineShape::SetAttachments(int from_attach
, int to_attach
) 
 465   m_attachmentFrom 
= from_attach
; 
 466   m_attachmentTo 
= to_attach
; 
 469 bool wxLineShape::HitTest(float x
, float y
, int *attachment
, float *distance
) 
 471   if (!m_lineControlPoints
) 
 474   // Look at label regions in case mouse is over a label 
 475   bool inLabelRegion 
= FALSE
; 
 476   for (int i 
= 0; i 
< 3; i 
++) 
 478     wxNode 
*regionNode 
= m_regions
.Nth(i
); 
 481       wxShapeRegion 
*region 
= (wxShapeRegion 
*)regionNode
->Data(); 
 482       if (region
->m_formattedText
.Number() > 0) 
 484         float xp
, yp
, cx
, cy
, cw
, ch
; 
 485         GetLabelPosition(i
, &xp
, &yp
); 
 486         // Offset region from default label position 
 487         region
->GetPosition(&cx
, &cy
); 
 488         region
->GetSize(&cw
, &ch
); 
 491         float rLeft 
= (float)(cx 
- (cw
/2.0)); 
 492         float rTop 
= (float)(cy 
- (ch
/2.0)); 
 493         float rRight 
= (float)(cx 
+ (cw
/2.0)); 
 494         float rBottom 
= (float)(cy 
+ (ch
/2.0)); 
 495         if (x 
> rLeft 
&& x 
< rRight 
&& y 
> rTop 
&& y 
< rBottom
) 
 497           inLabelRegion 
= TRUE
; 
 504   wxNode 
*node 
= m_lineControlPoints
->First(); 
 506   while (node 
&& node
->Next()) 
 508     wxRealPoint 
*point1 
= (wxRealPoint 
*)node
->Data(); 
 509     wxRealPoint 
*point2 
= (wxRealPoint 
*)node
->Next()->Data(); 
 511     // Allow for inaccurate mousing or vert/horiz lines 
 513     float left 
= wxMin(point1
->x
, point2
->x
) - extra
; 
 514     float right 
= wxMax(point1
->x
, point2
->x
) + extra
; 
 516     float bottom 
= wxMin(point1
->y
, point2
->y
) - extra
; 
 517     float top 
= wxMax(point1
->y
, point2
->y
) + extra
; 
 519     if ((x 
> left 
&& x 
< right 
&& y 
> bottom 
&& y 
< top
) || inLabelRegion
) 
 521       // Work out distance from centre of line 
 522       float centre_x 
= (float)(left 
+ (right 
- left
)/2.0); 
 523       float centre_y 
= (float)(bottom 
+ (top 
- bottom
)/2.0); 
 526       *distance 
= (float)sqrt((centre_x 
- x
)*(centre_x 
- x
) + (centre_y 
- y
)*(centre_y 
- y
)); 
 535 void wxLineShape::DrawArrows(wxDC
& dc
) 
 537   // Distance along line of each arrow: space them out evenly. 
 538   float startArrowPos 
= 0.0; 
 539   float endArrowPos 
= 0.0; 
 540   float middleArrowPos 
= 0.0; 
 542   wxNode 
*node 
= m_arcArrows
.First(); 
 545     wxArrowHead 
*arrow 
= (wxArrowHead 
*)node
->Data(); 
 546     switch (arrow
->GetArrowEnd()) 
 548       case ARROW_POSITION_START
: 
 550         if ((arrow
->GetXOffset() != 0.0) && !m_ignoreArrowOffsets
) 
 551           // If specified, x offset is proportional to line length 
 552           DrawArrow(dc
, arrow
, arrow
->GetXOffset(), TRUE
); 
 555           DrawArrow(dc
, arrow
, startArrowPos
, FALSE
);      // Absolute distance 
 556           startArrowPos 
+= arrow
->GetSize() + arrow
->GetSpacing(); 
 560       case ARROW_POSITION_END
: 
 562         if ((arrow
->GetXOffset() != 0.0) && !m_ignoreArrowOffsets
) 
 563           DrawArrow(dc
, arrow
, arrow
->GetXOffset(), TRUE
); 
 566           DrawArrow(dc
, arrow
, endArrowPos
, FALSE
); 
 567           endArrowPos 
+= arrow
->GetSize() + arrow
->GetSpacing(); 
 571       case ARROW_POSITION_MIDDLE
: 
 573         arrow
->SetXOffset(middleArrowPos
); 
 574         if ((arrow
->GetXOffset() != 0.0) && !m_ignoreArrowOffsets
) 
 575           DrawArrow(dc
, arrow
, arrow
->GetXOffset(), TRUE
); 
 578           DrawArrow(dc
, arrow
, middleArrowPos
, FALSE
); 
 579           middleArrowPos 
+= arrow
->GetSize() + arrow
->GetSpacing(); 
 588 void wxLineShape::DrawArrow(wxDC
& dc
, wxArrowHead 
*arrow
, float xOffset
, bool proportionalOffset
) 
 590   wxNode 
*first_line_node 
= m_lineControlPoints
->First(); 
 591   wxRealPoint 
*first_line_point 
= (wxRealPoint 
*)first_line_node
->Data(); 
 592   wxNode 
*second_line_node 
= first_line_node
->Next(); 
 593   wxRealPoint 
*second_line_point 
= (wxRealPoint 
*)second_line_node
->Data(); 
 595   wxNode 
*last_line_node 
= m_lineControlPoints
->Last(); 
 596   wxRealPoint 
*last_line_point 
= (wxRealPoint 
*)last_line_node
->Data(); 
 597   wxNode 
*second_last_line_node 
= last_line_node
->Previous(); 
 598   wxRealPoint 
*second_last_line_point 
= (wxRealPoint 
*)second_last_line_node
->Data(); 
 600   // Position where we want to start drawing 
 601   float positionOnLineX
, positionOnLineY
; 
 603   // Position of start point of line, at the end of which we draw the arrow. 
 604   float startPositionX
, startPositionY
; 
 606   switch (arrow
->GetPosition()) 
 608     case ARROW_POSITION_START
: 
 610       // If we're using a proportional offset, calculate just where this will 
 612       float realOffset 
= xOffset
; 
 613       if (proportionalOffset
) 
 616           (float)sqrt((second_line_point
->x 
- first_line_point
->x
)*(second_line_point
->x 
- first_line_point
->x
) + 
 617                       (second_line_point
->y 
- first_line_point
->y
)*(second_line_point
->y 
- first_line_point
->y
)); 
 618         realOffset 
= (float)(xOffset 
* totalLength
); 
 620       GetPointOnLine(second_line_point
->x
, second_line_point
->y
, 
 621                      first_line_point
->x
, first_line_point
->y
, 
 622                      realOffset
, &positionOnLineX
, &positionOnLineY
); 
 623       startPositionX 
= second_line_point
->x
; 
 624       startPositionY 
= second_line_point
->y
; 
 627     case ARROW_POSITION_END
: 
 629       // If we're using a proportional offset, calculate just where this will 
 631       float realOffset 
= xOffset
; 
 632       if (proportionalOffset
) 
 635           (float)sqrt((second_last_line_point
->x 
- last_line_point
->x
)*(second_last_line_point
->x 
- last_line_point
->x
) + 
 636                       (second_last_line_point
->y 
- last_line_point
->y
)*(second_last_line_point
->y 
- last_line_point
->y
)); 
 637         realOffset 
= (float)(xOffset 
* totalLength
); 
 639       GetPointOnLine(second_last_line_point
->x
, second_last_line_point
->y
, 
 640                      last_line_point
->x
, last_line_point
->y
, 
 641                      realOffset
, &positionOnLineX
, &positionOnLineY
); 
 642       startPositionX 
= second_last_line_point
->x
; 
 643       startPositionY 
= second_last_line_point
->y
; 
 646     case ARROW_POSITION_MIDDLE
: 
 648       // Choose a point half way between the last and penultimate points 
 649       float x 
= ((last_line_point
->x 
+ second_last_line_point
->x
)/2); 
 650       float y 
= ((last_line_point
->y 
+ second_last_line_point
->y
)/2); 
 652       // If we're using a proportional offset, calculate just where this will 
 654       float realOffset 
= xOffset
; 
 655       if (proportionalOffset
) 
 658           (float)sqrt((second_last_line_point
->x 
- x
)*(second_last_line_point
->x 
- x
) + 
 659                       (second_last_line_point
->y 
- y
)*(second_last_line_point
->y 
- y
)); 
 660         realOffset 
= (float)(xOffset 
* totalLength
); 
 663       GetPointOnLine(second_last_line_point
->x
, second_last_line_point
->y
, 
 664                      x
, y
, realOffset
, &positionOnLineX
, &positionOnLineY
); 
 665       startPositionX 
= second_last_line_point
->x
; 
 666       startPositionY 
= second_last_line_point
->y
; 
 672    * Add yOffset to arrow, if any 
 675   const float myPi 
= (float) 3.14159265; 
 676   // The translation that the y offset may give 
 679   if ((arrow
->GetYOffset() != 0.0) && !m_ignoreArrowOffsets
) 
 685        (x1, y1)--------------(x3, y3)------------------(x2, y2) 
 686        x4 = x3 - d * sin(theta) 
 687        y4 = y3 + d * cos(theta) 
 689        Where theta = tan(-1) of (y3-y1)/(x3-x1) 
 691      float x1 
= startPositionX
; 
 692      float y1 
= startPositionY
; 
 693      float x3 
= positionOnLineX
; 
 694      float y3 
= positionOnLineY
; 
 695      float d 
= -arrow
->GetYOffset(); // Negate so +offset is above line 
 699        theta 
= (float)(myPi
/2.0); 
 701        theta 
= (float)atan((y3
-y1
)/(x3
-x1
)); 
 703      float x4 
= (float)(x3 
- (d
*sin(theta
))); 
 704      float y4 
= (float)(y3 
+ (d
*cos(theta
))); 
 706      deltaX 
= x4 
- positionOnLineX
; 
 707      deltaY 
= y4 
- positionOnLineY
; 
 710   switch (arrow
->_GetType()) 
 714       float arrowLength 
= arrow
->GetSize(); 
 715       float arrowWidth 
= (float)(arrowLength
/3.0); 
 717       float tip_x
, tip_y
, side1_x
, side1_y
, side2_x
, side2_y
; 
 718       get_arrow_points(startPositionX
+deltaX
, startPositionY
+deltaY
, 
 719                        positionOnLineX
+deltaX
, positionOnLineY
+deltaY
, 
 720                        arrowLength
, arrowWidth
, &tip_x
, &tip_y
, 
 721                        &side1_x
, &side1_y
, &side2_x
, &side2_y
); 
 724       points
[0].x 
= tip_x
; points
[0].y 
= tip_y
; 
 725       points
[1].x 
= side1_x
; points
[1].y 
= side1_y
; 
 726       points
[2].x 
= side2_x
; points
[2].y 
= side2_y
; 
 727       points
[3].x 
= tip_x
; points
[3].y 
= tip_y
; 
 730       dc
.SetBrush(m_brush
); 
 731       dc
.DrawPolygon(4, points
); 
 734     case ARROW_HOLLOW_CIRCLE
: 
 735     case ARROW_FILLED_CIRCLE
: 
 737       // Find point on line of centre of circle, which is a radius away 
 738       // from the end position 
 739       float diameter 
= (float)(arrow
->GetSize()); 
 741       GetPointOnLine(startPositionX
+deltaX
, startPositionY
+deltaY
, 
 742                    positionOnLineX
+deltaX
, positionOnLineY
+deltaY
, 
 743                    (float)(diameter
/2.0), 
 746       // Convert ellipse centre to top-left coordinates 
 747       float x1 
= (float)(x 
- (diameter
/2.0)); 
 748       float y1 
= (float)(y 
- (diameter
/2.0)); 
 751       if (arrow
->_GetType() == ARROW_HOLLOW_CIRCLE
) 
 752         dc
.SetBrush(white_background_brush
); 
 754         dc
.SetBrush(m_brush
); 
 756       dc
.DrawEllipse(x1
, y1
, diameter
, diameter
); 
 759     case ARROW_SINGLE_OBLIQUE
: 
 765       if (arrow
->GetMetaFile()) 
 767         // Find point on line of centre of object, which is a half-width away 
 768         // from the end position 
 771          * <-- start pos  <-----><-- positionOnLineX 
 773          * --------------|  x  | <-- e.g. rectangular arrowhead 
 777         GetPointOnLine(startPositionX
, startPositionY
, 
 778                    positionOnLineX
, positionOnLineY
, 
 779                    (float)(arrow
->GetMetaFile()->m_width
/2.0), 
 782         // Calculate theta for rotating the metafile. 
 785           |     o(x2, y2)   'o' represents the arrowhead. 
 790           |______________________ 
 793         float x1 
= startPositionX
; 
 794         float y1 
= startPositionY
; 
 795         float x2 
= positionOnLineX
; 
 796         float y2 
= positionOnLineY
; 
 798         if ((x1 
== x2
) && (y1 
== y2
)) 
 801         else if ((x1 
== x2
) && (y1 
> y2
)) 
 802           theta 
= (float)(3.0*myPi
/2.0); 
 804         else if ((x1 
== x2
) && (y2 
> y1
)) 
 805           theta 
= (float)(myPi
/2.0); 
 807         else if ((x2 
> x1
) && (y2 
>= y1
)) 
 808           theta 
= (float)atan((y2 
- y1
)/(x2 
- x1
)); 
 811           theta 
= (float)(myPi 
+ atan((y2 
- y1
)/(x2 
- x1
))); 
 813         else if ((x2 
> x1
) && (y2 
< y1
)) 
 814           theta 
= (float)(2*myPi 
+ atan((y2 
- y1
)/(x2 
- x1
))); 
 818           wxFatalError("Unknown arrowhead rotation case in lines.cc"); 
 821         // Rotate about the centre of the object, then place 
 822         // the object on the line. 
 823         if (arrow
->GetMetaFile()->GetRotateable()) 
 824           arrow
->GetMetaFile()->Rotate(0.0, 0.0, theta
); 
 828           // If erasing, just draw a rectangle. 
 829           float minX
, minY
, maxX
, maxY
; 
 830           arrow
->GetMetaFile()->GetBounds(&minX
, &minY
, &maxX
, &maxY
); 
 831           // Make erasing rectangle slightly bigger or you get droppings. 
 833           dc
.DrawRectangle((float)(deltaX 
+ x 
+ minX 
- (extraPixels
/2.0)), (float)(deltaY 
+ y 
+ minY 
- (extraPixels
/2.0)), 
 834                            (float)(maxX 
- minX 
+ extraPixels
), (float)(maxY 
- minY 
+ extraPixels
)); 
 837           arrow
->GetMetaFile()->Draw(dc
, x
+deltaX
, y
+deltaY
); 
 847 void wxLineShape::OnErase(wxDC
& dc
) 
 849     wxPen 
*old_pen 
= m_pen
; 
 850     wxBrush 
*old_brush 
= m_brush
; 
 851     SetPen(white_background_pen
); 
 852     SetBrush(white_background_brush
); 
 854     float bound_x
, bound_y
; 
 855     GetBoundingBoxMax(&bound_x
, &bound_y
); 
 856     if (m_font
) dc
.SetFont(m_font
); 
 858     // Undraw text regions 
 859     for (int i 
= 0; i 
< 3; i
++) 
 861       wxNode 
*node 
= m_regions
.Nth(i
); 
 865         wxShapeRegion 
*region 
= (wxShapeRegion 
*)node
->Data(); 
 866         GetLabelPosition(i
, &x
, &y
); 
 867         EraseRegion(dc
, region
, x
, y
); 
 872     dc
.SetPen(white_background_pen
); 
 873     dc
.SetBrush(white_background_brush
); 
 875     // Drawing over the line only seems to work if the line has a thickness 
 877     if (old_pen 
&& (old_pen
->GetWidth() > 1)) 
 879       dc
.DrawRectangle((float)(m_xpos 
- (bound_x
/2.0) - 2.0), (float)(m_ypos 
- (bound_y
/2.0) - 2.0), 
 880                         (float)(bound_x
+4.0),  (float)(bound_y
+4.0)); 
 885       GetEventHandler()->OnDraw(dc
); 
 886       GetEventHandler()->OnEraseControlPoints(dc
); 
 890     if (old_pen
) SetPen(old_pen
); 
 891     if (old_brush
) SetBrush(old_brush
); 
 894 void wxLineShape::GetBoundingBoxMin(float *w
, float *h
) 
 901   wxNode 
*node 
= m_lineControlPoints
->First(); 
 904     wxRealPoint 
*point 
= (wxRealPoint 
*)node
->Data(); 
 906     if (point
->x 
< x1
) x1 
= point
->x
; 
 907     if (point
->y 
< y1
) y1 
= point
->y
; 
 908     if (point
->x 
> x2
) x2 
= point
->x
; 
 909     if (point
->y 
> y2
) y2 
= point
->y
; 
 913   *w 
= (float)(x2 
- x1
); 
 914   *h 
= (float)(y2 
- y1
); 
 918  * For a node image of interest, finds the position of this arc 
 919  * amongst all the arcs which are attached to THIS SIDE of the node image, 
 920  * and the number of same. 
 922 void wxLineShape::FindNth(wxShape 
*image
, int *nth
, int *no_arcs
, bool incoming
) 
 926   wxNode 
*node 
= image
->GetLines().First(); 
 929     this_attachment 
= m_attachmentTo
; 
 931     this_attachment 
= m_attachmentFrom
; 
 933   // Find number of lines going into/out of this particular attachment point 
 936     wxLineShape 
*line 
= (wxLineShape 
*)node
->Data(); 
 938     if (line
->m_from 
== image
) 
 940       // This is the nth line attached to 'image' 
 941       if ((line 
== this) && !incoming
) 
 944       // Increment num count if this is the same side (attachment number) 
 945       if (line
->m_attachmentFrom 
== this_attachment
) 
 949     if (line
->m_to 
== image
) 
 951       // This is the nth line attached to 'image' 
 952       if ((line 
== this) && incoming
) 
 955       // Increment num count if this is the same side (attachment number) 
 956       if (line
->m_attachmentTo 
== this_attachment
) 
 966 void wxLineShape::OnDrawOutline(wxDC
& dc
, float x
, float y
, float w
, float h
) 
 968   wxPen 
*old_pen 
= m_pen
; 
 969   wxBrush 
*old_brush 
= m_brush
; 
 971   wxPen 
dottedPen(wxColour(0, 0, 0), 1, wxDOT
); 
 973   SetBrush( wxTRANSPARENT_BRUSH 
); 
 977     dc.DrawSpline(m_lineControlPoints); 
 979     dc.DrawLines(m_lineControlPoints); 
 981   GetEventHandler()->OnDraw(dc
); 
 983   if (old_pen
) SetPen(old_pen
); 
 985   if (old_brush
) SetBrush(old_brush
); 
 989 bool wxLineShape::OnMovePre(wxDC
& dc
, float x
, float y
, float old_x
, float old_y
, bool display
) 
 991   float x_offset 
= x 
- old_x
; 
 992   float y_offset 
= y 
- old_y
; 
 994   if (m_lineControlPoints 
&& !(x_offset 
== 0.0 && y_offset 
== 0.0)) 
 996     wxNode 
*node 
= m_lineControlPoints
->First(); 
 999       wxRealPoint 
*point 
= (wxRealPoint 
*)node
->Data(); 
1000       point
->x 
+= x_offset
; 
1001       point
->y 
+= y_offset
; 
1002       node 
= node
->Next(); 
1007   // Move temporary label rectangles if necessary 
1008   for (int i 
= 0; i 
< 3; i
++) 
1010     if (m_labelObjects
[i
]) 
1012       m_labelObjects
[i
]->Erase(dc
); 
1013       float xp
, yp
, xr
, yr
; 
1014       GetLabelPosition(i
, &xp
, &yp
); 
1015       wxNode 
*node 
= m_regions
.Nth(i
); 
1018         wxShapeRegion 
*region 
= (wxShapeRegion 
*)node
->Data(); 
1019         region
->GetPosition(&xr
, &yr
); 
1026       m_labelObjects
[i
]->Move(dc
, xp
+xr
, yp
+yr
); 
1032 void wxLineShape::OnMoveLink(wxDC
& dc
, bool moveControlPoints
) 
1034   if (!m_from 
|| !m_to
) 
1037     if (m_lineControlPoints
->Number() > 2) 
1040     // Do each end - nothing in the middle. User has to move other points 
1041     // manually if necessary. 
1043     float other_end_x
, other_end_y
; 
1045     FindLineEndPoints(&end_x
, &end_y
, &other_end_x
, &other_end_y
); 
1047     wxNode 
*first 
= m_lineControlPoints
->First(); 
1048     wxRealPoint 
*first_point 
= (wxRealPoint 
*)first
->Data(); 
1049     wxNode 
*last 
= m_lineControlPoints
->Last(); 
1050     wxRealPoint 
*last_point 
= (wxRealPoint 
*)last
->Data(); 
1052 /* This is redundant, surely? Done by SetEnds. 
1053     first_point->x = end_x; first_point->y = end_y; 
1054     last_point->x = other_end_x; last_point->y = other_end_y; 
1057     float oldX 
= m_xpos
; 
1058     float oldY 
= m_ypos
; 
1060     SetEnds(end_x
, end_y
, other_end_x
, other_end_y
); 
1062     // Do a second time, because one may depend on the other. 
1063     FindLineEndPoints(&end_x
, &end_y
, &other_end_x
, &other_end_y
); 
1064     SetEnds(end_x
, end_y
, other_end_x
, other_end_y
); 
1066     // Try to move control points with the arc 
1067     float x_offset 
= m_xpos 
- oldX
; 
1068     float y_offset 
= m_ypos 
- oldY
; 
1070 //    if (moveControlPoints && m_lineControlPoints && !(x_offset == 0.0 && y_offset == 0.0)) 
1071     // Only move control points if it's a self link. And only works if attachment mode is ON. 
1072     if ((m_from 
== m_to
) && m_from
->GetAttachmentMode() && moveControlPoints 
&& m_lineControlPoints 
&& !(x_offset 
== 0.0 && y_offset 
== 0.0)) 
1074       wxNode 
*node 
= m_lineControlPoints
->First(); 
1077         if ((node 
!= m_lineControlPoints
->First()) && (node 
!= m_lineControlPoints
->Last())) 
1079           wxRealPoint 
*point 
= (wxRealPoint 
*)node
->Data(); 
1080           point
->x 
+= x_offset
; 
1081           point
->y 
+= y_offset
; 
1083         node 
= node
->Next(); 
1087     Move(dc
, m_xpos
, m_ypos
); 
1090 // Finds the x, y points at the two ends of the line. 
1091 // This function can be used by e.g. line-routing routines to 
1092 // get the actual points on the two node images where the lines will be drawn 
1094 void wxLineShape::FindLineEndPoints(float *fromX
, float *fromY
, float *toX
, float *toY
) 
1096   if (!m_from 
|| !m_to
) 
1099   // Do each end - nothing in the middle. User has to move other points 
1100   // manually if necessary. 
1102   float other_end_x
, other_end_y
; 
1104   wxNode 
*first 
= m_lineControlPoints
->First(); 
1105   wxRealPoint 
*first_point 
= (wxRealPoint 
*)first
->Data(); 
1106   wxNode 
*last 
= m_lineControlPoints
->Last(); 
1107   wxRealPoint 
*last_point 
= (wxRealPoint 
*)last
->Data(); 
1109   wxNode 
*second 
= first
->Next(); 
1110   wxRealPoint 
*second_point 
= (wxRealPoint 
*)second
->Data(); 
1112   wxNode 
*second_last 
= last
->Previous(); 
1113   wxRealPoint 
*second_last_point 
= (wxRealPoint 
*)second_last
->Data(); 
1115   if (m_lineControlPoints
->Number() > 2) 
1117     if (m_from
->GetAttachmentMode()) 
1120       FindNth(m_from
, &nth
, &no_arcs
, FALSE
); // Not incoming 
1121       m_from
->GetAttachmentPosition(m_attachmentFrom
, &end_x
, &end_y
, nth
, no_arcs
, this); 
1124       (void) m_from
->GetPerimeterPoint(m_from
->GetX(), m_from
->GetY(), 
1125                                    (float)second_point
->x
, (float)second_point
->y
, 
1128     if (m_to
->GetAttachmentMode()) 
1131       FindNth(m_to
, &nth
, &no_arcs
, TRUE
); // Incoming 
1132       m_to
->GetAttachmentPosition(m_attachmentTo
, &other_end_x
, &other_end_y
, nth
, no_arcs
, this); 
1135       (void) m_to
->GetPerimeterPoint(m_to
->GetX(), m_to
->GetY(), 
1136                                 (float)second_last_point
->x
, (float)second_last_point
->y
, 
1137                                 &other_end_x
, &other_end_y
); 
1141     float fromX 
= m_from
->GetX(); 
1142     float fromY 
= m_from
->GetY(); 
1143     float toX 
= m_to
->GetX(); 
1144     float toY 
= m_to
->GetY(); 
1146     if (m_from
->GetAttachmentMode()) 
1149       FindNth(m_from
, &nth
, &no_arcs
, FALSE
); 
1150       m_from
->GetAttachmentPosition(m_attachmentFrom
, &end_x
, &end_y
, nth
, no_arcs
, this); 
1155     if (m_to
->GetAttachmentMode()) 
1158       FindNth(m_to
, &nth
, &no_arcs
, TRUE
); 
1159       m_to
->GetAttachmentPosition(m_attachmentTo
, &other_end_x
, &other_end_y
, nth
, no_arcs
, this); 
1164     if (!m_from
->GetAttachmentMode()) 
1165       (void) m_from
->GetPerimeterPoint(m_from
->GetX(), m_from
->GetY(), 
1169     if (!m_to
->GetAttachmentMode()) 
1170       (void) m_to
->GetPerimeterPoint(m_to
->GetX(), m_to
->GetY(), 
1172                                 &other_end_x
, &other_end_y
); 
1180 void wxLineShape::OnDraw(wxDC
& dc
) 
1182   if (m_lineControlPoints
) 
1187       dc
.SetBrush(m_brush
); 
1189     int n 
= m_lineControlPoints
->Number(); 
1190     wxPoint 
*points 
= new wxPoint
[n
]; 
1192     for (i 
= 0; i 
< n
; i
++) 
1194         wxRealPoint
* point 
= (wxRealPoint
*) m_lineControlPoints
->Nth(i
)->Data(); 
1195         points
[i
].x 
= (int) point
->x
; 
1196         points
[i
].y 
= (int) point
->y
; 
1200       dc
.DrawSpline(n
, points
); 
1202       dc
.DrawLines(n
, points
); 
1206     // Problem with pen - if not a solid pen, does strange things 
1207     // to the arrowhead. So make (get) a new pen that's solid. 
1208     if (m_pen 
&& (m_pen
->GetStyle() != wxSOLID
)) 
1211         wxThePenList
->FindOrCreatePen(m_pen
->GetColour(), 1, wxSOLID
); 
1213         dc
.SetPen(solid_pen
); 
1219 void wxLineShape::OnDrawControlPoints(wxDC
& dc
) 
1224   // Draw temporary label rectangles if necessary 
1225   for (int i 
= 0; i 
< 3; i
++) 
1227     if (m_labelObjects
[i
]) 
1228       m_labelObjects
[i
]->Draw(dc
); 
1230   wxShape::OnDrawControlPoints(dc
); 
1233 void wxLineShape::OnEraseControlPoints(wxDC
& dc
) 
1235   // Erase temporary label rectangles if necessary 
1236   for (int i 
= 0; i 
< 3; i
++) 
1238     if (m_labelObjects
[i
]) 
1239       m_labelObjects
[i
]->Erase(dc
); 
1241   wxShape::OnEraseControlPoints(dc
); 
1244 void wxLineShape::OnDragLeft(bool draw
, float x
, float y
, int keys
, int attachment
) 
1248 void wxLineShape::OnBeginDragLeft(float x
, float y
, int keys
, int attachment
) 
1252 void wxLineShape::OnEndDragLeft(float x
, float y
, int keys
, int attachment
) 
1257 void wxLineShape::SetArrowSize(float length, float width) 
1259   arrow_length = length; 
1260   arrow_width = width; 
1263 void wxLineShape::SetStartArrow(int style) 
1265   start_style = style; 
1268 void wxLineShape::SetMiddleArrow(int style) 
1270   middle_style = style; 
1273 void wxLineShape::SetEndArrow(int style) 
1279 void wxLineShape::OnDrawContents(wxDC
& dc
) 
1281   if (GetDisableLabel()) 
1284   for (int i 
= 0; i 
< 3; i
++) 
1286     wxNode 
*node 
= m_regions
.Nth(i
); 
1289       wxShapeRegion 
*region 
= (wxShapeRegion 
*)node
->Data(); 
1291       GetLabelPosition(i
, &x
, &y
); 
1292       DrawRegion(dc
, region
, x
, y
); 
1299 char *wxLineShape::GetFunctor() 
1305 void wxLineShape::SetTo(wxShape 
*object
) 
1310 void wxLineShape::SetFrom(wxShape 
*object
) 
1315 void wxLineShape::MakeControlPoints() 
1317   if (m_canvas 
&& m_lineControlPoints
) 
1319     wxNode 
*first 
= m_lineControlPoints
->First(); 
1320     wxNode 
*last 
= m_lineControlPoints
->Last(); 
1321     wxRealPoint 
*first_point 
= (wxRealPoint 
*)first
->Data(); 
1322     wxRealPoint 
*last_point 
= (wxRealPoint 
*)last
->Data(); 
1324     wxLineControlPoint 
*control 
= new wxLineControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
,  
1325                                                first_point
->x
, first_point
->y
, 
1326                                                CONTROL_POINT_ENDPOINT_FROM
); 
1327     control
->m_point 
= first_point
; 
1328     m_canvas
->AddShape(control
); 
1329     m_controlPoints
.Append(control
); 
1332     wxNode 
*node 
= first
->Next(); 
1333     while (node 
!= last
) 
1335       wxRealPoint 
*point 
= (wxRealPoint 
*)node
->Data(); 
1337       control 
= new wxLineControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
,  
1339                                                CONTROL_POINT_LINE
); 
1340       control
->m_point 
= point
; 
1342       m_canvas
->AddShape(control
); 
1343       m_controlPoints
.Append(control
); 
1345       node 
= node
->Next(); 
1347     control 
= new wxLineControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
,  
1348                                                last_point
->x
, last_point
->y
, 
1349                                                CONTROL_POINT_ENDPOINT_TO
); 
1350     control
->m_point 
= last_point
; 
1351     m_canvas
->AddShape(control
); 
1352     m_controlPoints
.Append(control
); 
1358 void wxLineShape::ResetControlPoints() 
1360   if (m_canvas 
&& m_lineControlPoints 
&& m_controlPoints
.Number() > 0) 
1362     wxNode 
*node 
= m_controlPoints
.First(); 
1363     wxNode 
*control_node 
= m_lineControlPoints
->First(); 
1364     while (node 
&& control_node
) 
1366       wxRealPoint 
*point 
= (wxRealPoint 
*)control_node
->Data(); 
1367       wxLineControlPoint 
*control 
= (wxLineControlPoint 
*)node
->Data(); 
1368       control
->SetX(point
->x
); 
1369       control
->SetY(point
->y
); 
1371       node 
= node
->Next(); 
1372       control_node 
= control_node
->Next(); 
1378 void wxLineShape::WritePrologAttributes(wxExpr 
*clause
) 
1380   wxShape::WritePrologAttributes(clause
); 
1383     clause
->AddAttributeValue("from", m_from
->GetId()); 
1385     clause
->AddAttributeValue("to", m_to
->GetId()); 
1387   if (m_attachmentTo 
!= 0) 
1388     clause
->AddAttributeValue("attachment_to", (long)m_attachmentTo
); 
1389   if (m_attachmentFrom 
!= 0) 
1390     clause
->AddAttributeValue("attachment_from", (long)m_attachmentFrom
); 
1392   if (m_alignmentStart 
!= 0) 
1393     clause
->AddAttributeValue("align_start", (long)m_alignmentStart
); 
1394   if (m_alignmentEnd 
!= 0) 
1395     clause
->AddAttributeValue("align_end", (long)m_alignmentEnd
); 
1397   clause
->AddAttributeValue("is_spline", (long)m_isSpline
); 
1398   if (m_maintainStraightLines
) 
1399     clause
->AddAttributeValue("keep_lines_straight", (long)m_maintainStraightLines
); 
1401   // Make a list of lists for the (sp)line controls 
1402   wxExpr 
*list 
= new wxExpr(PrologList
); 
1403   wxNode 
*node 
= m_lineControlPoints
->First(); 
1406     wxRealPoint 
*point 
= (wxRealPoint 
*)node
->Data(); 
1407     wxExpr 
*point_list 
= new wxExpr(PrologList
); 
1408     wxExpr 
*x_expr 
= new wxExpr((float) point
->x
); 
1409     wxExpr 
*y_expr 
= new wxExpr((float) point
->y
); 
1410     point_list
->Append(x_expr
); 
1411     point_list
->Append(y_expr
); 
1412     list
->Append(point_list
); 
1414     node 
= node
->Next(); 
1416   clause
->AddAttributeValue("controls", list
); 
1418   // Write arc arrows in new OGL format, if there are any. 
1419   // This is a list of lists. Each sublist comprises: 
1420   // (arrowType arrowEnd xOffset arrowSize) 
1421   if (m_arcArrows
.Number() > 0) 
1423     wxExpr 
*arrow_list 
= new wxExpr(PrologList
); 
1424     node 
= m_arcArrows
.First(); 
1427       wxArrowHead 
*head 
= (wxArrowHead 
*)node
->Data(); 
1428       wxExpr 
*head_list 
= new wxExpr(PrologList
); 
1429       head_list
->Append(new wxExpr((long)head
->_GetType())); 
1430       head_list
->Append(new wxExpr((long)head
->GetArrowEnd())); 
1431       head_list
->Append(new wxExpr(head
->GetXOffset())); 
1432       head_list
->Append(new wxExpr(head
->GetArrowSize())); 
1433       head_list
->Append(new wxExpr(PrologString
, (head
->GetName() ? head
->GetName() : ""))); 
1434       head_list
->Append(new wxExpr(head
->GetId())); 
1436       // New members of wxArrowHead 
1437       head_list
->Append(new wxExpr(head
->GetYOffset())); 
1438       head_list
->Append(new wxExpr(head
->GetSpacing())); 
1440       arrow_list
->Append(head_list
); 
1442       node 
= node
->Next(); 
1444     clause
->AddAttributeValue("arrows", arrow_list
); 
1448 void wxLineShape::ReadPrologAttributes(wxExpr 
*clause
) 
1450   wxShape::ReadPrologAttributes(clause
); 
1452   int iVal 
= (int) m_isSpline
; 
1453   clause
->AssignAttributeValue("is_spline", &iVal
); 
1454   m_isSpline 
= (iVal 
!= 0); 
1456   iVal 
= (int) m_maintainStraightLines
; 
1457   clause
->AssignAttributeValue("keep_lines_straight", &iVal
); 
1458   m_maintainStraightLines 
= (iVal 
!= 0); 
1460   clause
->AssignAttributeValue("align_start", &m_alignmentStart
); 
1461   clause
->AssignAttributeValue("align_end", &m_alignmentEnd
); 
1463   // Compatibility: check for no regions. 
1464   if (m_regions
.Number() == 0) 
1466     wxShapeRegion 
*newRegion 
= new wxShapeRegion
; 
1467     newRegion
->SetName("Middle"); 
1468     newRegion
->SetSize(150, 50); 
1469     m_regions
.Append((wxObject 
*)newRegion
); 
1470     if (m_text
.Number() > 0) 
1472       newRegion
->ClearText(); 
1473       wxNode 
*node 
= m_text
.First(); 
1476         wxShapeTextLine 
*textLine 
= (wxShapeTextLine 
*)node
->Data(); 
1477         wxNode 
*next 
= node
->Next(); 
1478         newRegion
->GetFormattedText().Append((wxObject 
*)textLine
); 
1484     newRegion 
= new wxShapeRegion
; 
1485     newRegion
->SetName("Start"); 
1486     newRegion
->SetSize(150, 50); 
1487     m_regions
.Append((wxObject 
*)newRegion
);   
1489     newRegion 
= new wxShapeRegion
; 
1490     newRegion
->SetName("End"); 
1491     newRegion
->SetSize(150, 50); 
1492     m_regions
.Append((wxObject 
*)newRegion
); 
1496   m_attachmentFrom 
= 0; 
1498   clause
->AssignAttributeValue("attachment_to", &m_attachmentTo
); 
1499   clause
->AssignAttributeValue("attachmen_from", &m_attachmentFrom
); 
1501   wxExpr 
*line_list 
= NULL
; 
1503   // When image is created, there are default control points. Override 
1504   // them if there are some in the file. 
1505   clause
->AssignAttributeValue("controls", &line_list
); 
1509     // Read a list of lists for the spline controls 
1510     if (m_lineControlPoints
) 
1512       ClearPointList(*m_lineControlPoints
); 
1515       m_lineControlPoints 
= new wxList
; 
1517     wxExpr 
*node 
= line_list
->value
.first
; 
1521       wxExpr 
*xexpr 
= node
->value
.first
; 
1522       float x 
= xexpr
->RealValue(); 
1524       wxExpr 
*yexpr 
= xexpr
->next
; 
1525       float y 
= yexpr
->RealValue(); 
1527       wxRealPoint 
*point 
= new wxRealPoint(x
, y
); 
1528       m_lineControlPoints
->Append((wxObject
*) point
); 
1534   // Read arrow list, for new OGL code 
1535   wxExpr 
*arrow_list 
= NULL
; 
1537   clause
->AssignAttributeValue("arrows", &arrow_list
); 
1540     wxExpr 
*node 
= arrow_list
->value
.first
; 
1544       WXTYPE arrowType 
= ARROW_ARROW
; 
1546       float xOffset 
= 0.0; 
1547       float arrowSize 
= 0.0; 
1548       wxString 
arrowName(""); 
1551       wxExpr 
*type_expr 
= node
->Nth(0); 
1552       wxExpr 
*end_expr 
= node
->Nth(1); 
1553       wxExpr 
*dist_expr 
= node
->Nth(2); 
1554       wxExpr 
*size_expr 
= node
->Nth(3); 
1555       wxExpr 
*name_expr 
= node
->Nth(4); 
1556       wxExpr 
*id_expr 
= node
->Nth(5); 
1558       // New members of wxArrowHead 
1559       wxExpr 
*yOffsetExpr 
= node
->Nth(6); 
1560       wxExpr 
*spacingExpr 
= node
->Nth(7); 
1563         arrowType 
= (int)type_expr
->IntegerValue(); 
1565         arrowEnd 
= (int)end_expr
->IntegerValue(); 
1567         xOffset 
= dist_expr
->RealValue(); 
1569         arrowSize 
= size_expr
->RealValue(); 
1571         arrowName 
= name_expr
->StringValue(); 
1573         arrowId 
= id_expr
->IntegerValue(); 
1578         RegisterId(arrowId
); 
1580       wxArrowHead 
*arrowHead 
= AddArrow(arrowType
, arrowEnd
, arrowSize
, xOffset
, (char*) (const char*) arrowName
, NULL
, arrowId
); 
1582         arrowHead
->SetYOffset(yOffsetExpr
->RealValue()); 
1584         arrowHead
->SetSpacing(spacingExpr
->RealValue()); 
1592 void wxLineShape::Copy(wxShape
& copy
) 
1594   wxShape::Copy(copy
); 
1596   wxASSERT( copy
.IsKindOf(CLASSINFO(wxLineShape
)) ); 
1598   wxLineShape
& lineCopy 
= (wxLineShape
&) copy
; 
1600   lineCopy
.m_isSpline 
= m_isSpline
; 
1601   lineCopy
.m_alignmentStart 
= m_alignmentStart
; 
1602   lineCopy
.m_alignmentEnd 
= m_alignmentEnd
; 
1603   lineCopy
.m_maintainStraightLines 
= m_maintainStraightLines
; 
1604   lineCopy
.m_lineOrientations
.Clear(); 
1605   wxNode 
*node 
= m_lineOrientations
.First(); 
1608     lineCopy
.m_lineOrientations
.Append(node
->Data()); 
1609     node 
= node
->Next(); 
1612   if (lineCopy
.m_lineControlPoints
) 
1614     ClearPointList(*lineCopy
.m_lineControlPoints
); 
1615     delete lineCopy
.m_lineControlPoints
; 
1618   lineCopy
.m_lineControlPoints 
= new wxList
; 
1620   node 
= m_lineControlPoints
->First(); 
1623     wxRealPoint 
*point 
= (wxRealPoint 
*)node
->Data(); 
1624     wxRealPoint 
*new_point 
= new wxRealPoint(point
->x
, point
->y
); 
1625     lineCopy
.m_lineControlPoints
->Append((wxObject
*) new_point
); 
1626     node 
= node
->Next(); 
1630   lineCopy.start_style = start_style; 
1631   lineCopy.end_style = end_style; 
1632   lineCopy.middle_style = middle_style; 
1634   lineCopy.arrow_length = arrow_length; 
1635   lineCopy.arrow_width = arrow_width; 
1638   // Copy new OGL stuff 
1639   lineCopy
.ClearArrowsAtPosition(-1); 
1640   node 
= m_arcArrows
.First(); 
1643     wxArrowHead 
*arrow 
= (wxArrowHead 
*)node
->Data(); 
1644     lineCopy
.m_arcArrows
.Append(new wxArrowHead(*arrow
)); 
1645     node 
= node
->Next(); 
1649 // Override select, to create/delete temporary label-moving objects 
1650 void wxLineShape::Select(bool select
, wxDC
* dc
) 
1652   wxShape::Select(select
); 
1655     for (int i 
= 0; i 
< 3; i
++) 
1657       wxNode 
*node 
= m_regions
.Nth(i
); 
1660         wxShapeRegion 
*region 
= (wxShapeRegion 
*)node
->Data(); 
1661         if (region
->m_formattedText
.Number() > 0) 
1663           float w
, h
, x
, y
, xx
, yy
; 
1664           region
->GetSize(&w
, &h
); 
1665           region
->GetPosition(&x
, &y
); 
1666           GetLabelPosition(i
, &xx
, &yy
); 
1667           if (m_labelObjects
[i
]) 
1669             m_labelObjects
[i
]->Select(FALSE
); 
1670             m_labelObjects
[i
]->RemoveFromCanvas(m_canvas
); 
1671             delete m_labelObjects
[i
]; 
1673           m_labelObjects
[i
] = new wxLabelShape(this, region
, w
, h
); 
1674           m_labelObjects
[i
]->AddToCanvas(m_canvas
); 
1675           m_labelObjects
[i
]->Show(TRUE
); 
1677             m_labelObjects
[i
]->Move(*dc
, (float)(x 
+ xx
), (float)(y 
+ yy
)); 
1678           m_labelObjects
[i
]->Select(TRUE
); 
1685     for (int i 
= 0; i 
< 3; i
++) 
1687       if (m_labelObjects
[i
]) 
1689         m_labelObjects
[i
]->Select(FALSE
, dc
); 
1690         m_labelObjects
[i
]->RemoveFromCanvas(m_canvas
); 
1691         delete m_labelObjects
[i
]; 
1692         m_labelObjects
[i
] = NULL
; 
1699  * Line control point 
1703 IMPLEMENT_DYNAMIC_CLASS(wxLineControlPoint
, wxControlPoint
) 
1705 wxLineControlPoint::wxLineControlPoint(wxShapeCanvas 
*theCanvas
, wxShape 
*object
, float size
, float x
, float y
, int the_type
): 
1706   wxControlPoint(theCanvas
, object
, size
, x
, y
, the_type
) 
1713 wxLineControlPoint::~wxLineControlPoint() 
1717 void wxLineControlPoint::OnDraw(wxDC
& dc
) 
1719   wxRectangleShape::OnDraw(dc
); 
1722 // Implement movement of Line point 
1723 void wxLineControlPoint::OnDragLeft(bool draw
, float x
, float y
, int keys
, int attachment
) 
1725     m_shape
->GetEventHandler()->OnSizingDragLeft(this, draw
, x
, y
, keys
, attachment
); 
1728 void wxLineControlPoint::OnBeginDragLeft(float x
, float y
, int keys
, int attachment
) 
1730     m_shape
->GetEventHandler()->OnSizingBeginDragLeft(this, x
, y
, keys
, attachment
); 
1733 void wxLineControlPoint::OnEndDragLeft(float x
, float y
, int keys
, int attachment
) 
1735     m_shape
->GetEventHandler()->OnSizingEndDragLeft(this, x
, y
, keys
, attachment
); 
1738 // Control points ('handles') redirect control to the actual shape, to make it easier 
1739 // to override sizing behaviour. 
1740 void wxLineShape::OnSizingDragLeft(wxControlPoint
* pt
, bool draw
, float x
, float y
, int keys
, int attachment
) 
1742   wxLineControlPoint
* lpt 
= (wxLineControlPoint
*) pt
; 
1744   wxClientDC 
dc(GetCanvas()); 
1745   GetCanvas()->PrepareDC(dc
); 
1747   dc
.SetLogicalFunction(wxXOR
); 
1749   wxPen 
dottedPen(wxColour(0, 0, 0), 1, wxDOT
); 
1750   dc
.SetPen(dottedPen
); 
1751   dc
.SetBrush((* wxTRANSPARENT_BRUSH
)); 
1753   if (lpt
->m_type 
== CONTROL_POINT_LINE
) 
1755     m_canvas
->Snap(&x
, &y
); 
1757     lpt
->SetX(x
); lpt
->SetY(y
); 
1758     lpt
->m_point
->x 
= x
; lpt
->m_point
->y 
= y
; 
1760     wxLineShape 
*lineShape 
= (wxLineShape 
*)this; 
1762     wxPen 
*old_pen 
= lineShape
->GetPen(); 
1763     wxBrush 
*old_brush 
= lineShape
->GetBrush(); 
1765     wxPen 
dottedPen(wxColour(0, 0, 0), 1, wxDOT
); 
1766     lineShape
->SetPen(& dottedPen
); 
1767     lineShape
->SetBrush(wxTRANSPARENT_BRUSH
); 
1769     lineShape
->GetEventHandler()->OnMoveLink(dc
, FALSE
); 
1771     lineShape
->SetPen(old_pen
); 
1772     lineShape
->SetBrush(old_brush
); 
1775   if (lpt
->m_type 
== CONTROL_POINT_ENDPOINT_FROM 
|| lpt
->m_type 
== CONTROL_POINT_ENDPOINT_TO
) 
1777     lpt
->SetX(x
); lpt
->SetY(y
); 
1782 void wxLineShape::OnSizingBeginDragLeft(wxControlPoint
* pt
, float x
, float y
, int keys
, int attachment
) 
1784   wxLineControlPoint
* lpt 
= (wxLineControlPoint
*) pt
; 
1786   wxClientDC 
dc(GetCanvas()); 
1787   GetCanvas()->PrepareDC(dc
); 
1789   wxLineShape 
*lineShape 
= (wxLineShape 
*)this; 
1790   if (lpt
->m_type 
== CONTROL_POINT_LINE
) 
1792     m_canvas
->Snap(&x
, &y
); 
1796     // Redraw start and end objects because we've left holes 
1797     // when erasing the line 
1798     lineShape
->GetFrom()->OnDraw(dc
); 
1799     lineShape
->GetFrom()->OnDrawContents(dc
); 
1800     lineShape
->GetTo()->OnDraw(dc
); 
1801     lineShape
->GetTo()->OnDrawContents(dc
); 
1803     this->SetDisableLabel(TRUE
); 
1804     dc
.SetLogicalFunction(wxXOR
); 
1806     lpt
->m_xpos 
= x
; lpt
->m_ypos 
= y
; 
1807     lpt
->m_point
->x 
= x
; lpt
->m_point
->y 
= y
; 
1809     wxPen 
*old_pen 
= lineShape
->GetPen(); 
1810     wxBrush 
*old_brush 
= lineShape
->GetBrush(); 
1812     wxPen 
dottedPen(wxColour(0, 0, 0), 1, wxDOT
); 
1813     lineShape
->SetPen(& dottedPen
); 
1814     lineShape
->SetBrush(wxTRANSPARENT_BRUSH
); 
1816     lineShape
->GetEventHandler()->OnMoveLink(dc
, FALSE
); 
1818     lineShape
->SetPen(old_pen
); 
1819     lineShape
->SetBrush(old_brush
); 
1822   if (lpt
->m_type 
== CONTROL_POINT_ENDPOINT_FROM 
|| lpt
->m_type 
== CONTROL_POINT_ENDPOINT_TO
) 
1825     lineShape
->OnDraw(dc
); 
1826     if (lpt
->m_type 
== CONTROL_POINT_ENDPOINT_FROM
) 
1828       lineShape
->GetFrom()->OnDraw(dc
); 
1829       lineShape
->GetFrom()->OnDrawContents(dc
); 
1833       lineShape
->GetTo()->OnDraw(dc
); 
1834       lineShape
->GetTo()->OnDrawContents(dc
); 
1836     m_canvas
->SetCursor(GraphicsBullseyeCursor
); 
1837     lpt
->m_oldCursor 
= wxSTANDARD_CURSOR
; 
1841 void wxLineShape::OnSizingEndDragLeft(wxControlPoint
* pt
, float x
, float y
, int keys
, int attachment
) 
1843   wxLineControlPoint
* lpt 
= (wxLineControlPoint
*) pt
; 
1845   wxClientDC 
dc(GetCanvas()); 
1846   GetCanvas()->PrepareDC(dc
); 
1848   this->SetDisableLabel(FALSE
); 
1849   wxLineShape 
*lineShape 
= (wxLineShape 
*)this; 
1851   if (lpt
->m_type 
== CONTROL_POINT_LINE
) 
1853     m_canvas
->Snap(&x
, &y
); 
1855     dc
.SetLogicalFunction(wxCOPY
); 
1856     lpt
->m_xpos 
= x
; lpt
->m_ypos 
= y
; 
1857     lpt
->m_point
->x 
= x
; lpt
->m_point
->y 
= y
; 
1859     lineShape
->GetEventHandler()->OnMoveLink(dc
); 
1861   if (lpt
->m_type 
== CONTROL_POINT_ENDPOINT_FROM
) 
1863     if (lpt
->m_oldCursor
) 
1864       m_canvas
->SetCursor(lpt
->m_oldCursor
); 
1867     lpt
->m_xpos 
= x
; lpt
->m_ypos 
= y
; 
1869     if (lineShape
->GetFrom()) 
1871       lineShape
->GetFrom()->MoveLineToNewAttachment(dc
, lineShape
, x
, y
); 
1872       lineShape
->GetFrom()->MoveLinks(dc
); 
1875   if (lpt
->m_type 
== CONTROL_POINT_ENDPOINT_TO
) 
1877     if (lpt
->m_oldCursor
) 
1878       m_canvas
->SetCursor(lpt
->m_oldCursor
); 
1880     lpt
->m_xpos 
= x
; lpt
->m_ypos 
= y
; 
1882     if (lineShape
->GetTo()) 
1884       lineShape
->GetTo()->MoveLineToNewAttachment(dc
, lineShape
, x
, y
); 
1885       lineShape
->GetTo()->MoveLinks(dc
); 
1889   for (i 
= 0; i 
< lineShape
->GetLineControlPoints()->Number(); i
++) 
1890     if (((wxRealPoint 
*)(lineShape
->GetLineControlPoints()->Nth(i
)->Data())) == lpt
->m_point
) 
1893   // N.B. in OnMoveControlPoint, an event handler in Hardy could have deselected 
1894   // the line and therefore deleted 'this'. -> GPF, intermittently. 
1895   // So assume at this point that we've been blown away. 
1896   wxLineShape 
*lineObj 
= lineShape
; 
1897   wxShapeCanvas 
*objCanvas 
= m_canvas
; 
1899   lineObj
->OnMoveControlPoint(i
+1, x
, y
); 
1901   if (!objCanvas
->GetQuickEditMode()) objCanvas
->Redraw(dc
); 
1904 // Implement movement of endpoint to a new attachment 
1905 void wxLineControlPoint::OnDragRight(bool draw
, float x
, float y
, int keys
, int attachment
) 
1907   if (m_type 
== CONTROL_POINT_ENDPOINT_FROM 
|| m_type 
== CONTROL_POINT_ENDPOINT_TO
) 
1909     m_xpos 
= x
; m_ypos 
= y
; 
1913 void wxLineControlPoint::OnBeginDragRight(float x
, float y
, int keys
, int attachment
) 
1915   wxClientDC 
dc(GetCanvas()); 
1916   GetCanvas()->PrepareDC(dc
); 
1918   wxLineShape 
*lineShape 
= (wxLineShape 
*)m_shape
; 
1919   if (m_type 
== CONTROL_POINT_ENDPOINT_FROM 
|| m_type 
== CONTROL_POINT_ENDPOINT_TO
) 
1922     lineShape
->GetEventHandler()->OnDraw(dc
); 
1923     if (m_type 
== CONTROL_POINT_ENDPOINT_FROM
) 
1925       lineShape
->GetFrom()->GetEventHandler()->OnDraw(dc
); 
1926       lineShape
->GetFrom()->GetEventHandler()->OnDrawContents(dc
); 
1930       lineShape
->GetTo()->GetEventHandler()->OnDraw(dc
); 
1931       lineShape
->GetTo()->GetEventHandler()->OnDrawContents(dc
); 
1933     m_canvas
->SetCursor(GraphicsBullseyeCursor
); 
1934     m_oldCursor 
= wxSTANDARD_CURSOR
; 
1938 void wxLineControlPoint::OnEndDragRight(float x
, float y
, int keys
, int attachment
) 
1940   wxClientDC 
dc(GetCanvas()); 
1941   GetCanvas()->PrepareDC(dc
); 
1943   wxLineShape 
*lineShape 
= (wxLineShape 
*)m_shape
; 
1944   if (m_type 
== CONTROL_POINT_ENDPOINT_FROM
) 
1947       m_canvas
->SetCursor(m_oldCursor
); 
1949     m_xpos 
= x
; m_ypos 
= y
; 
1951     if (lineShape
->GetFrom()) 
1953       lineShape
->GetFrom()->EraseLinks(dc
); 
1958       if (lineShape
->GetFrom()->HitTest(x
, y
, &new_attachment
, &distance
)) 
1959         lineShape
->SetAttachments(new_attachment
, lineShape
->GetAttachmentTo()); 
1961       lineShape
->GetFrom()->MoveLinks(dc
); 
1964   if (m_type 
== CONTROL_POINT_ENDPOINT_TO
) 
1967       m_canvas
->SetCursor(m_oldCursor
); 
1970     m_xpos 
= x
; m_ypos 
= y
; 
1972     if (lineShape
->GetTo()) 
1974       lineShape
->GetTo()->EraseLinks(dc
); 
1978       if (lineShape
->GetTo()->HitTest(x
, y
, &new_attachment
, &distance
)) 
1979         lineShape
->SetAttachments(lineShape
->GetAttachmentFrom(), new_attachment
); 
1981       lineShape
->GetTo()->MoveLinks(dc
); 
1985   for (i 
= 0; i 
< lineShape
->GetLineControlPoints()->Number(); i
++) 
1986     if (((wxRealPoint 
*)(lineShape
->GetLineControlPoints()->Nth(i
)->Data())) == m_point
) 
1988   lineShape
->OnMoveControlPoint(i
+1, x
, y
); 
1989   if (!m_canvas
->GetQuickEditMode()) m_canvas
->Redraw(dc
); 
1993  * Get the point on the given line (x1, y1) (x2, y2) 
1994  * distance 'length' along from the end, 
1995  * returned values in x and y 
1998 void GetPointOnLine(float x1
, float y1
, float x2
, float y2
, 
1999                     float length
, float *x
, float *y
) 
2001   float l 
= (float)sqrt((x2 
- x1
)*(x2 
- x1
) + (y2 
- y1
)*(y2 
- y1
)); 
2006   float i_bar 
= (x2 
- x1
)/l
; 
2007   float j_bar 
= (y2 
- y1
)/l
; 
2009   *x 
= (- length
*i_bar
) + x2
; 
2010   *y 
= (- length
*j_bar
) + y2
; 
2013 wxArrowHead 
*wxLineShape::AddArrow(WXTYPE type
, int end
, float size
, float xOffset
, 
2014     const wxString
& name
, wxPseudoMetaFile 
*mf
, long arrowId
) 
2016   wxArrowHead 
*arrow 
= new wxArrowHead(type
, end
, size
, xOffset
, name
, mf
, arrowId
); 
2017   m_arcArrows
.Append(arrow
); 
2022  * Add arrowhead at a particular position in the arrowhead list. 
2024 bool wxLineShape::AddArrowOrdered(wxArrowHead 
*arrow
, wxList
& referenceList
, int end
) 
2026   wxNode 
*refNode 
= referenceList
.First(); 
2027   wxNode 
*currNode 
= m_arcArrows
.First(); 
2028   wxString 
targetName(arrow
->GetName()); 
2029   if (!refNode
) return FALSE
; 
2031   // First check whether we need to insert in front of list, 
2032   // because this arrowhead is the first in the reference 
2033   // list and should therefore be first in the current list. 
2034   wxArrowHead 
*refArrow 
= (wxArrowHead 
*)refNode
->Data(); 
2035   if (refArrow
->GetName() == targetName
) 
2037     m_arcArrows
.Insert(arrow
); 
2041   while (refNode 
&& currNode
) 
2043     wxArrowHead 
*currArrow 
= (wxArrowHead 
*)currNode
->Data(); 
2044     refArrow 
= (wxArrowHead 
*)refNode
->Data(); 
2046     // Matching: advance current arrow pointer 
2047     if ((currArrow
->GetArrowEnd() == end
) && 
2048         (currArrow
->GetName() == refArrow
->GetName())) 
2050       currNode 
= currNode
->Next(); // Could be NULL now 
2052         currArrow 
= (wxArrowHead 
*)currNode
->Data(); 
2055     // Check if we're at the correct position in the 
2057     if (targetName 
== refArrow
->GetName()) 
2060         m_arcArrows
.Insert(currNode
, arrow
); 
2062         m_arcArrows
.Append(arrow
); 
2065     refNode 
= refNode
->Next(); 
2067   m_arcArrows
.Append(arrow
); 
2071 void wxLineShape::ClearArrowsAtPosition(int end
) 
2073   wxNode 
*node 
= m_arcArrows
.First(); 
2076     wxArrowHead 
*arrow 
= (wxArrowHead 
*)node
->Data(); 
2077     wxNode 
*next 
= node
->Next(); 
2086       case ARROW_POSITION_START
: 
2088         if (arrow
->GetArrowEnd() == ARROW_POSITION_START
) 
2095       case ARROW_POSITION_END
: 
2097         if (arrow
->GetArrowEnd() == ARROW_POSITION_END
) 
2104       case ARROW_POSITION_MIDDLE
: 
2106         if (arrow
->GetArrowEnd() == ARROW_POSITION_MIDDLE
) 
2118 bool wxLineShape::ClearArrow(const wxString
& name
) 
2120   wxNode 
*node 
= m_arcArrows
.First(); 
2123     wxArrowHead 
*arrow 
= (wxArrowHead 
*)node
->Data(); 
2124     if (arrow
->GetName() == name
) 
2130     node 
= node
->Next(); 
2136  * Finds an arrowhead at the given position (if -1, any position) 
2140 wxArrowHead 
*wxLineShape::FindArrowHead(int position
, const wxString
& name
) 
2142   wxNode 
*node 
= m_arcArrows
.First(); 
2145     wxArrowHead 
*arrow 
= (wxArrowHead 
*)node
->Data(); 
2146     if (((position 
== -1) || (position 
== arrow
->GetArrowEnd())) && 
2147         (arrow
->GetName() == name
)) 
2149     node 
= node
->Next(); 
2154 wxArrowHead 
*wxLineShape::FindArrowHead(long arrowId
) 
2156   wxNode 
*node 
= m_arcArrows
.First(); 
2159     wxArrowHead 
*arrow 
= (wxArrowHead 
*)node
->Data(); 
2160     if (arrowId 
== arrow
->GetId()) 
2162     node 
= node
->Next(); 
2168  * Deletes an arrowhead at the given position (if -1, any position) 
2172 bool wxLineShape::DeleteArrowHead(int position
, const wxString
& name
) 
2174   wxNode 
*node 
= m_arcArrows
.First(); 
2177     wxArrowHead 
*arrow 
= (wxArrowHead 
*)node
->Data(); 
2178     if (((position 
== -1) || (position 
== arrow
->GetArrowEnd())) && 
2179         (arrow
->GetName() == name
)) 
2185     node 
= node
->Next(); 
2190 // Overloaded DeleteArrowHead: pass arrowhead id. 
2191 bool wxLineShape::DeleteArrowHead(long id
) 
2193   wxNode 
*node 
= m_arcArrows
.First(); 
2196     wxArrowHead 
*arrow 
= (wxArrowHead 
*)node
->Data(); 
2197     if (arrow
->GetId() == id
) 
2203     node 
= node
->Next(); 
2209  * Calculate the minimum width a line 
2210  * occupies, for the purposes of drawing lines in tools. 
2214 float wxLineShape::FindMinimumWidth() 
2216   float minWidth 
= 0.0; 
2217   wxNode 
*node 
= m_arcArrows
.First(); 
2220     wxArrowHead 
*arrowHead 
= (wxArrowHead 
*)node
->Data(); 
2221     minWidth 
+= arrowHead
->GetSize(); 
2223       minWidth 
+= arrowHead
->GetSpacing(); 
2225     node 
= node
->Next(); 
2227   // We have ABSOLUTE minimum now. So 
2228   // scale it to give it reasonable aesthetics 
2229   // when drawing with line. 
2231     minWidth 
= (float)(minWidth 
* 1.4); 
2235   SetEnds(0.0, 0.0, minWidth
, 0.0); 
2241 // Find which position we're talking about at this (x, y). 
2242 // Returns ARROW_POSITION_START, ARROW_POSITION_MIDDLE, ARROW_POSITION_END 
2243 int wxLineShape::FindLinePosition(float x
, float y
) 
2245   float startX
, startY
, endX
, endY
; 
2246   GetEnds(&startX
, &startY
, &endX
, &endY
); 
2248   // Find distances from centre, start and end. The smallest wins. 
2249   float centreDistance 
= (float)(sqrt((x 
- m_xpos
)*(x 
- m_xpos
) + (y 
- m_ypos
)*(y 
- m_ypos
))); 
2250   float startDistance 
= (float)(sqrt((x 
- startX
)*(x 
- startX
) + (y 
- startY
)*(y 
- startY
))); 
2251   float endDistance 
= (float)(sqrt((x 
- endX
)*(x 
- endX
) + (y 
- endY
)*(y 
- endY
))); 
2253   if (centreDistance 
< startDistance 
&& centreDistance 
< endDistance
) 
2254     return ARROW_POSITION_MIDDLE
; 
2255   else if (startDistance 
< endDistance
) 
2256     return ARROW_POSITION_START
; 
2258     return ARROW_POSITION_END
; 
2261 // Set alignment flags 
2262 void wxLineShape::SetAlignmentOrientation(bool isEnd
, bool isHoriz
) 
2266     if (isHoriz 
&& ((m_alignmentEnd 
& LINE_ALIGNMENT_HORIZ
) != LINE_ALIGNMENT_HORIZ
)) 
2267       m_alignmentEnd 
|= LINE_ALIGNMENT_HORIZ
; 
2268     else if (!isHoriz 
&& ((m_alignmentEnd 
& LINE_ALIGNMENT_HORIZ
) == LINE_ALIGNMENT_HORIZ
)) 
2269       m_alignmentEnd 
-= LINE_ALIGNMENT_HORIZ
; 
2273     if (isHoriz 
&& ((m_alignmentStart 
& LINE_ALIGNMENT_HORIZ
) != LINE_ALIGNMENT_HORIZ
)) 
2274       m_alignmentStart 
|= LINE_ALIGNMENT_HORIZ
; 
2275     else if (!isHoriz 
&& ((m_alignmentStart 
& LINE_ALIGNMENT_HORIZ
) == LINE_ALIGNMENT_HORIZ
)) 
2276       m_alignmentStart 
-= LINE_ALIGNMENT_HORIZ
; 
2280 void wxLineShape::SetAlignmentType(bool isEnd
, int alignType
) 
2284     if (alignType 
== LINE_ALIGNMENT_TO_NEXT_HANDLE
) 
2286       if ((m_alignmentEnd 
& LINE_ALIGNMENT_TO_NEXT_HANDLE
) != LINE_ALIGNMENT_TO_NEXT_HANDLE
) 
2287         m_alignmentEnd 
|= LINE_ALIGNMENT_TO_NEXT_HANDLE
; 
2289     else if ((m_alignmentEnd 
& LINE_ALIGNMENT_TO_NEXT_HANDLE
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
) 
2290       m_alignmentEnd 
-= LINE_ALIGNMENT_TO_NEXT_HANDLE
; 
2294     if (alignType 
== LINE_ALIGNMENT_TO_NEXT_HANDLE
) 
2296       if ((m_alignmentStart 
& LINE_ALIGNMENT_TO_NEXT_HANDLE
) != LINE_ALIGNMENT_TO_NEXT_HANDLE
) 
2297         m_alignmentStart 
|= LINE_ALIGNMENT_TO_NEXT_HANDLE
; 
2299     else if ((m_alignmentStart 
& LINE_ALIGNMENT_TO_NEXT_HANDLE
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
) 
2300       m_alignmentStart 
-= LINE_ALIGNMENT_TO_NEXT_HANDLE
; 
2304 bool wxLineShape::GetAlignmentOrientation(bool isEnd
) 
2307     return ((m_alignmentEnd 
& LINE_ALIGNMENT_HORIZ
) == LINE_ALIGNMENT_HORIZ
); 
2309     return ((m_alignmentStart 
& LINE_ALIGNMENT_HORIZ
) == LINE_ALIGNMENT_HORIZ
); 
2312 int wxLineShape::GetAlignmentType(bool isEnd
) 
2315     return (m_alignmentEnd 
& LINE_ALIGNMENT_TO_NEXT_HANDLE
); 
2317     return (m_alignmentStart 
& LINE_ALIGNMENT_TO_NEXT_HANDLE
); 
2320 wxRealPoint 
*wxLineShape::GetNextControlPoint(wxShape 
*nodeObject
) 
2322   int n 
= m_lineControlPoints
->Number(); 
2324   if (m_to 
== nodeObject
) 
2326     // Must be END of line, so we want (n - 1)th control point. 
2327     // But indexing ends at n-1, so subtract 2. 
2331   wxNode 
*node 
= m_lineControlPoints
->Nth(nn
); 
2334     return (wxRealPoint 
*)node
->Data(); 
2345 IMPLEMENT_DYNAMIC_CLASS(wxArrowHead
, wxObject
) 
2347 wxArrowHead::wxArrowHead(WXTYPE type
, int end
, float size
, float dist
, const wxString
& name
, 
2348                      wxPseudoMetaFile 
*mf
, long arrowId
) 
2350   m_arrowType 
= type
; m_arrowEnd 
= end
; m_arrowSize 
= size
; 
2362 wxArrowHead::wxArrowHead(wxArrowHead
& toCopy
) 
2364   m_arrowType 
= toCopy
.m_arrowType
; m_arrowEnd 
= toCopy
.GetArrowEnd(); 
2365   m_arrowSize 
= toCopy
.m_arrowSize
; 
2366   m_xOffset 
= toCopy
.m_xOffset
; 
2367   m_yOffset 
= toCopy
.m_yOffset
; 
2368   m_spacing 
= toCopy
.m_spacing
; 
2369   m_arrowName 
= toCopy
.m_arrowName 
; 
2370   if (toCopy
.m_metaFile
) 
2371     m_metaFile 
= new wxPseudoMetaFile(*(toCopy
.m_metaFile
)); 
2377 wxArrowHead::~wxArrowHead() 
2379   if (m_metaFile
) delete m_metaFile
; 
2382 void wxArrowHead::SetSize(float size
) 
2385   if ((m_arrowType 
== ARROW_METAFILE
) && m_metaFile
) 
2387     float oldWidth 
= m_metaFile
->m_width
; 
2388     if (oldWidth 
== 0.0) 
2391     float scale 
= (float)(size
/oldWidth
); 
2393       m_metaFile
->Scale(scale
, scale
); 
2402 IMPLEMENT_DYNAMIC_CLASS(wxLabelShape
, wxRectangleShape
) 
2404 wxLabelShape::wxLabelShape(wxLineShape 
*parent
, wxShapeRegion 
*region
, float w
, float h
):wxRectangleShape(w
, h
) 
2406   m_lineShape 
= parent
; 
2407   m_shapeRegion 
= region
; 
2408   SetPen(wxThePenList
->FindOrCreatePen(wxColour(0, 0, 0), 1, wxDOT
)); 
2411 wxLabelShape::~wxLabelShape() 
2415 void wxLabelShape::OnDraw(wxDC
& dc
) 
2417   if (m_lineShape 
&& !m_lineShape
->GetDrawHandles()) 
2420     float x1 
= (float)(m_xpos 
- m_width
/2.0); 
2421     float y1 
= (float)(m_ypos 
- m_height
/2.0); 
2425       if (m_pen
->GetWidth() == 0) 
2426         dc
.SetPen(transparent_pen
); 
2430     dc
.SetBrush(wxTRANSPARENT_BRUSH
); 
2432     if (m_cornerRadius 
> 0.0) 
2433       dc
.DrawRoundedRectangle(x1
, y1
, m_width
, m_height
, m_cornerRadius
); 
2435       dc
.DrawRectangle(x1
, y1
, m_width
, m_height
); 
2438 void wxLabelShape::OnDrawContents(wxDC
& dc
) 
2442 void wxLabelShape::OnDragLeft(bool draw
, float x
, float y
, int keys
, int attachment
) 
2444   wxRectangleShape::OnDragLeft(draw
, x
, y
, keys
, attachment
); 
2447 void wxLabelShape::OnBeginDragLeft(float x
, float y
, int keys
, int attachment
) 
2449   wxRectangleShape::OnBeginDragLeft(x
, y
, keys
, attachment
); 
2452 void wxLabelShape::OnEndDragLeft(float x
, float y
, int keys
, int attachment
) 
2454   wxRectangleShape::OnEndDragLeft(x
, y
, keys
, attachment
); 
2457 bool wxLabelShape::OnMovePre(wxDC
& dc
, float x
, float y
, float old_x
, float old_y
, bool display
) 
2459   m_shapeRegion
->SetSize(m_width
, m_height
); 
2461   // Find position in line's region list 
2463   wxNode 
*node 
= m_lineShape
->GetRegions().First(); 
2466     if (m_shapeRegion 
== (wxShapeRegion 
*)node
->Data()) 
2470       node 
= node
->Next(); 
2475   m_lineShape
->GetLabelPosition(i
, &xx
, &yy
); 
2476   // Set the region's offset, relative to the default position for 
2478   m_shapeRegion
->SetPosition((float)(x 
- xx
), (float)(y 
- yy
)); 
2480   // Need to reformat to fit region. 
2481   if (m_shapeRegion
->GetText()) 
2484     wxString 
s(m_shapeRegion
->GetText()); 
2485     m_lineShape
->FormatText(dc
, s
, i
); 
2486     m_lineShape
->DrawRegion(dc
, m_shapeRegion
, xx
, yy
); 
2491 // Divert left and right clicks to line object 
2492 void wxLabelShape::OnLeftClick(float x
, float y
, int keys
, int attachment
) 
2494   m_lineShape
->GetEventHandler()->OnLeftClick(x
, y
, keys
, attachment
); 
2497 void wxLabelShape::OnRightClick(float x
, float y
, int keys
, int attachment
) 
2499   m_lineShape
->GetEventHandler()->OnRightClick(x
, y
, keys
, attachment
);