1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     Basic OGL classes (2) 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  15 // For compilers that support precompilation, includes "wx.h". 
  16 #include <wx/wxprec.h> 
  27 #include <wx/wxexpr.h> 
  48 // Control point types 
  49 // Rectangle and most other shapes 
  50 #define CONTROL_POINT_VERTICAL   1 
  51 #define CONTROL_POINT_HORIZONTAL 2 
  52 #define CONTROL_POINT_DIAGONAL   3 
  55 #define CONTROL_POINT_ENDPOINT_TO 4 
  56 #define CONTROL_POINT_ENDPOINT_FROM 5 
  57 #define CONTROL_POINT_LINE       6 
  59 // Two stage construction: need to call Create 
  60 IMPLEMENT_DYNAMIC_CLASS(wxPolygonShape
, wxShape
) 
  62 wxPolygonShape::wxPolygonShape() 
  65   m_originalPoints 
= NULL
; 
  68 void wxPolygonShape::Create(wxList 
*the_points
) 
  70   m_originalPoints 
= the_points
; 
  72   // Duplicate the list of points 
  73   m_points 
= new wxList
; 
  75   wxNode 
*node 
= the_points
->First(); 
  78     wxRealPoint 
*point 
= (wxRealPoint 
*)node
->Data(); 
  79     wxRealPoint 
*new_point 
= new wxRealPoint(point
->x
, point
->y
); 
  80     m_points
->Append((wxObject
*) new_point
); 
  83   CalculateBoundingBox(); 
  84   m_originalWidth 
= m_boundWidth
; 
  85   m_originalHeight 
= m_boundHeight
; 
  86   SetDefaultRegionSize(); 
  89 wxPolygonShape::~wxPolygonShape() 
  93     wxNode 
*node 
= m_points
->First(); 
  96       wxRealPoint 
*point 
= (wxRealPoint 
*)node
->Data(); 
  99       node 
= m_points
->First(); 
 103   if (m_originalPoints
) 
 105     wxNode 
*node 
= m_originalPoints
->First(); 
 108       wxRealPoint 
*point 
= (wxRealPoint 
*)node
->Data(); 
 111       node 
= m_originalPoints
->First(); 
 113     delete m_originalPoints
; 
 118 // Width and height. Centre of object is centre of box. 
 119 void wxPolygonShape::GetBoundingBoxMin(float *width
, float *height
) 
 121   *width 
= m_boundWidth
; 
 122   *height 
= m_boundHeight
; 
 125 void wxPolygonShape::CalculateBoundingBox() 
 127   // Calculate bounding box at construction (and presumably resize) time 
 129   float right 
= -10000; 
 131   float bottom 
= -10000; 
 133   wxNode 
*node 
= m_points
->First(); 
 136     wxRealPoint 
*point 
= (wxRealPoint 
*)node
->Data(); 
 137     if (point
->x 
< left
) left 
= point
->x
; 
 138     if (point
->x 
> right
) right 
= point
->x
; 
 140     if (point
->y 
< top
) top 
= point
->y
; 
 141     if (point
->y 
> bottom
) bottom 
= point
->y
; 
 145   m_boundWidth 
= right 
- left
; 
 146   m_boundHeight 
= bottom 
- top
; 
 149 // Recalculates the centre of the polygon, and 
 150 // readjusts the point offsets accordingly. 
 151 // Necessary since the centre of the polygon 
 152 // is expected to be the real centre of the bounding 
 154 void wxPolygonShape::CalculatePolygonCentre() 
 157   float right 
= -10000; 
 159   float bottom 
= -10000; 
 161   wxNode 
*node 
= m_points
->First(); 
 164     wxRealPoint 
*point 
= (wxRealPoint 
*)node
->Data(); 
 165     if (point
->x 
< left
) left 
= point
->x
; 
 166     if (point
->x 
> right
) right 
= point
->x
; 
 168     if (point
->y 
< top
) top 
= point
->y
; 
 169     if (point
->y 
> bottom
) bottom 
= point
->y
; 
 173   float bwidth 
= right 
- left
; 
 174   float bheight 
= bottom 
- top
; 
 176   float newCentreX 
= (float)(left 
+ (bwidth
/2.0)); 
 177   float newCentreY 
= (float)(top 
+ (bheight
/2.0)); 
 179   node 
= m_points
->First(); 
 182     wxRealPoint 
*point 
= (wxRealPoint 
*)node
->Data(); 
 183     point
->x 
-= newCentreX
; 
 184     point
->y 
-= newCentreY
; 
 187   m_xpos 
+= newCentreX
; 
 188   m_ypos 
+= newCentreY
; 
 191 bool PolylineHitTest(float n
, float xvec
[], float yvec
[], 
 192                            float x1
, float y1
, float x2
, float y2
) 
 196   float lastx 
= xvec
[0]; 
 197   float lasty 
= yvec
[0]; 
 199   float min_ratio 
= 1.0; 
 204   for (i 
= 1; i 
< n
; i
++) 
 206     check_line_intersection(x1
, y1
, x2
, y2
, lastx
, lasty
, xvec
[i
], yvec
[i
], 
 207                             &line_ratio
, &other_ratio
); 
 208     if (line_ratio 
!= 1.0) 
 210 //    sprintf(buf, "Line ratio = %.2f, other ratio = %.2f\n", line_ratio, other_ratio); 
 211 //    ClipsErrorFunction(buf); 
 215     if (line_ratio 
< min_ratio
) 
 216       min_ratio 
= line_ratio
; 
 219   // Do last (implicit) line if last and first floats are not identical 
 220   if (!(xvec
[0] == lastx 
&& yvec
[0] == lasty
)) 
 222     check_line_intersection(x1
, y1
, x2
, y2
, lastx
, lasty
, xvec
[0], yvec
[0], 
 223                             &line_ratio
, &other_ratio
); 
 224     if (line_ratio 
!= 1.0) 
 226 //    sprintf(buf, "Line ratio = %.2f, other ratio = %.2f\n", line_ratio, other_ratio); 
 227 //    ClipsErrorFunction(buf); 
 229     if (line_ratio 
< min_ratio
) 
 230       min_ratio 
= line_ratio
; 
 232 //  ClipsErrorFunction("\n"); 
 236 bool wxPolygonShape::HitTest(float x
, float y
, int *attachment
, float *distance
) 
 238   // Imagine four lines radiating from this point. If all of these lines hit the polygon, 
 239   // we're inside it, otherwise we're not. Obviously we'd need more radiating lines 
 240   // to be sure of correct results for very strange (concave) shapes. 
 245   endPointsY
[0] = (float)(y 
- 1000.0); 
 247   endPointsX
[1] = (float)(x 
+ 1000.0); 
 251   endPointsY
[2] = (float)(y 
+ 1000.0); 
 253   endPointsX
[3] = (float)(x 
- 1000.0); 
 256   // Store polygon points in an array 
 257   int np 
= m_points
->Number(); 
 258   float *xpoints 
= new float[np
]; 
 259   float *ypoints 
= new float[np
]; 
 260   wxNode 
*node 
= m_points
->First(); 
 264     wxRealPoint 
*point 
= (wxRealPoint 
*)node
->Data(); 
 265     xpoints
[i
] = point
->x 
+ m_xpos
; 
 266     ypoints
[i
] = point
->y 
+ m_ypos
; 
 271   // We assume it's inside the polygon UNLESS one or more 
 272   // lines don't hit the outline. 
 273   bool isContained 
= TRUE
; 
 276   for (i 
= 0; i 
< noPoints
; i
++) 
 278     if (!PolylineHitTest(np
, xpoints
, ypoints
, x
, y
, endPointsX
[i
], endPointsY
[i
])) 
 283     ClipsErrorFunction("It's a hit!\n"); 
 285     ClipsErrorFunction("No hit.\n"); 
 293   int nearest_attachment 
= 0; 
 295   // If a hit, check the attachment points within the object. 
 296   int n 
= GetNumberOfAttachments(); 
 297   float nearest 
= 999999.0; 
 299   for (i 
= 0; i 
< n
; i
++) 
 302     if (GetAttachmentPosition(i
, &xp
, &yp
)) 
 304       float l 
= (float)sqrt(((xp 
- x
) * (xp 
- x
)) + 
 305                  ((yp 
- y
) * (yp 
- y
))); 
 309         nearest_attachment 
= i
; 
 313   *attachment 
= nearest_attachment
; 
 318 // Really need to be able to reset the shape! Otherwise, if the 
 319 // points ever go to zero, we've lost it, and can't resize. 
 320 void wxPolygonShape::SetSize(float new_width
, float new_height
, bool recursive
) 
 322   SetAttachmentSize(new_width
, new_height
); 
 324   // Multiply all points by proportion of new size to old size 
 325   float x_proportion 
= (float)(fabs(new_width
/m_originalWidth
)); 
 326   float y_proportion 
= (float)(fabs(new_height
/m_originalHeight
)); 
 328   wxNode 
*node 
= m_points
->First(); 
 329   wxNode 
*original_node 
= m_originalPoints
->First(); 
 330   while (node 
&& original_node
) 
 332     wxRealPoint 
*point 
= (wxRealPoint 
*)node
->Data(); 
 333     wxRealPoint 
*original_point 
= (wxRealPoint 
*)original_node
->Data(); 
 335     point
->x 
= (original_point
->x 
* x_proportion
); 
 336     point
->y 
= (original_point
->y 
* y_proportion
); 
 339     original_node 
= original_node
->Next(); 
 342 //  CalculateBoundingBox(); 
 343   m_boundWidth 
= (float)fabs(new_width
); 
 344   m_boundHeight 
= (float)fabs(new_height
); 
 345   SetDefaultRegionSize(); 
 348 // Make the original points the same as the working points 
 349 void wxPolygonShape::UpdateOriginalPoints() 
 351   if (!m_originalPoints
) m_originalPoints 
= new wxList
; 
 352   wxNode 
*original_node 
= m_originalPoints
->First(); 
 353   while (original_node
) 
 355     wxNode 
*next_node 
= original_node
->Next(); 
 356     wxRealPoint 
*original_point 
= (wxRealPoint 
*)original_node
->Data(); 
 357     delete original_point
; 
 358     delete original_node
; 
 360     original_node 
= next_node
; 
 363   wxNode 
*node 
= m_points
->First(); 
 366     wxRealPoint 
*point 
= (wxRealPoint 
*)node
->Data(); 
 367     wxRealPoint 
*original_point 
= new wxRealPoint(point
->x
, point
->y
); 
 368     m_originalPoints
->Append((wxObject
*) original_point
); 
 372   CalculateBoundingBox(); 
 373   m_originalWidth 
= m_boundWidth
; 
 374   m_originalHeight 
= m_boundHeight
; 
 377 void wxPolygonShape::AddPolygonPoint(int pos
) 
 379   wxNode 
*node 
= m_points
->Nth(pos
); 
 380   if (!node
) node 
= m_points
->First(); 
 381   wxRealPoint 
*firstPoint 
= (wxRealPoint 
*)node
->Data(); 
 383   wxNode 
*node2 
= m_points
->Nth(pos 
+ 1); 
 384   if (!node2
) node2 
= m_points
->First(); 
 385   wxRealPoint 
*secondPoint 
= (wxRealPoint 
*)node2
->Data(); 
 387   float x 
= (float)((secondPoint
->x 
- firstPoint
->x
)/2.0 + firstPoint
->x
); 
 388   float y 
= (float)((secondPoint
->y 
- firstPoint
->y
)/2.0 + firstPoint
->y
); 
 389   wxRealPoint 
*point 
= new wxRealPoint(x
, y
); 
 391   if (pos 
>= (m_points
->Number() - 1)) 
 392     m_points
->Append((wxObject
*) point
); 
 394     m_points
->Insert(node2
, (wxObject
*) point
); 
 396   UpdateOriginalPoints(); 
 400     DeleteControlPoints(); 
 405 void wxPolygonShape::DeletePolygonPoint(int pos
) 
 407   wxNode 
*node 
= m_points
->Nth(pos
); 
 410     wxRealPoint 
*point 
= (wxRealPoint 
*)node
->Data(); 
 413     UpdateOriginalPoints(); 
 416       DeleteControlPoints(); 
 422 // Assume (x1, y1) is centre of box (most generally, line end at box) 
 423 bool wxPolygonShape::GetPerimeterPoint(float x1
, float y1
, 
 425                                      float *x3
, float *y3
) 
 427   int n 
= m_points
->Number(); 
 429   // First check for situation where the line is vertical, 
 430   // and we would want to connect to a point on that vertical -- 
 431   // find_end_for_polyline can't cope with this (the arrow 
 432   // gets drawn to the wrong place). 
 433   if ((!m_attachmentMode
) && (x1 
== x2
)) 
 435     // Look for the point we'd be connecting to. This is 
 437     wxNode 
*node 
= m_points
->First(); 
 440       wxRealPoint 
*point 
= (wxRealPoint 
*)node
->Data(); 
 443         if ((y2 
> y1
) && (point
->y 
> 0.0)) 
 445           *x3 
= point
->x 
+ m_xpos
; 
 446           *y3 
= point
->y 
+ m_ypos
; 
 449         else if ((y2 
< y1
) && (point
->y 
< 0.0)) 
 451           *x3 
= point
->x 
+ m_xpos
; 
 452           *y3 
= point
->y 
+ m_ypos
; 
 460   float *xpoints 
= new float[n
]; 
 461   float *ypoints 
= new float[n
]; 
 463   wxNode 
*node 
= m_points
->First(); 
 467     wxRealPoint 
*point 
= (wxRealPoint 
*)node
->Data(); 
 468     xpoints
[i
] = point
->x 
+ m_xpos
; 
 469     ypoints
[i
] = point
->y 
+ m_ypos
; 
 474   wxRealPoint *point = (wxRealPoint *)m_points->First()->Data(); 
 475   xpoints[i] = point->x + m_xpos; 
 476   ypoints[i] = point->y + m_ypos; 
 479   find_end_for_polyline(n
, xpoints
, ypoints
,  
 480                         x1
, y1
, x2
, y2
, x3
, y3
); 
 488 void wxPolygonShape::OnDraw(wxDC
& dc
) 
 490     int n 
= m_points
->Number(); 
 491     wxPoint 
*intPoints 
= new wxPoint
[n
]; 
 493     for (i 
= 0; i 
< n
; i
++) 
 495       wxRealPoint
* point 
= (wxRealPoint
*) m_points
->Nth(i
)->Data(); 
 496       intPoints
[i
].x 
= (int) point
->x
; 
 497       intPoints
[i
].y 
= (int) point
->y
; 
 500     if (m_shadowMode 
!= SHADOW_NONE
) 
 503         dc
.SetBrush(m_shadowBrush
); 
 504       dc
.SetPen(transparent_pen
); 
 506       dc
.DrawPolygon(n
, intPoints
, m_xpos 
+ m_shadowOffsetX
, m_ypos 
+ m_shadowOffsetY
); 
 511       if (m_pen
->GetWidth() == 0) 
 512         dc
.SetPen(transparent_pen
); 
 517       dc
.SetBrush(m_brush
); 
 518     dc
.DrawPolygon(n
, intPoints
, m_xpos
, m_ypos
); 
 523 void wxPolygonShape::OnDrawOutline(wxDC
& dc
, float x
, float y
, float w
, float h
) 
 525   dc
.SetBrush(wxTRANSPARENT_BRUSH
); 
 527   int n 
= m_points
->Number(); 
 528   wxPoint 
*intPoints 
= new wxPoint
[n
]; 
 530   for (i 
= 0; i 
< n
; i
++) 
 532     wxRealPoint
* point 
= (wxRealPoint
*) m_points
->Nth(i
)->Data(); 
 533     intPoints
[i
].x 
= (int) point
->x
; 
 534     intPoints
[i
].y 
= (int) point
->y
; 
 536   dc
.DrawPolygon(n
, intPoints
, x
, y
); 
 537 //  wxShape::OnDrawOutline(x, y, w, h); 
 540 // Make as many control points as there are vertices. 
 541 void wxPolygonShape::MakeControlPoints() 
 543   wxNode 
*node 
= m_points
->First(); 
 546     wxRealPoint 
*point 
= (wxRealPoint 
*)node
->Data(); 
 547     wxPolygonControlPoint 
*control 
= new wxPolygonControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, 
 548       point
, point
->x
, point
->y
); 
 549     m_canvas
->AddShape(control
); 
 550     m_controlPoints
.Append(control
); 
 555   float maxX, maxY, minX, minY; 
 557   GetBoundingBoxMax(&maxX, &maxY); 
 558   GetBoundingBoxMin(&minX, &minY); 
 560   float widthMin = (float)(minX + CONTROL_POINT_SIZE + 2); 
 561   float heightMin = (float)(minY + CONTROL_POINT_SIZE + 2); 
 563   // Offsets from main object 
 564   float top = (float)(- (heightMin / 2.0)); 
 565   float bottom = (float)(heightMin / 2.0 + (maxY - minY)); 
 566   float left = (float)(- (widthMin / 2.0)); 
 567   float right = (float)(widthMin / 2.0 + (maxX - minX)); 
 569   wxControlPoint *control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, top,  
 570                                            CONTROL_POINT_DIAGONAL); 
 571   m_canvas->AddShape(control); 
 572   m_controlPoints.Append(control); 
 574   control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, 0, top,  
 575                                            CONTROL_POINT_VERTICAL); 
 576   m_canvas->AddShape(control); 
 577   m_controlPoints.Append(control); 
 579   control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, top,  
 580                                            CONTROL_POINT_DIAGONAL); 
 581   m_canvas->AddShape(control); 
 582   m_controlPoints.Append(control); 
 584   control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, 0,  
 585                                            CONTROL_POINT_HORIZONTAL); 
 586   m_canvas->AddShape(control); 
 587   m_controlPoints.Append(control); 
 589   control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, bottom,  
 590                                            CONTROL_POINT_DIAGONAL); 
 591   m_canvas->AddShape(control); 
 592   m_controlPoints.Append(control); 
 594   control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, 0, bottom,  
 595                                            CONTROL_POINT_VERTICAL); 
 596   m_canvas->AddShape(control); 
 597   m_controlPoints.Append(control); 
 599   control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, bottom,  
 600                                            CONTROL_POINT_DIAGONAL); 
 601   m_canvas->AddShape(control); 
 602   m_controlPoints.Append(control); 
 604   control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, 0,  
 605                                            CONTROL_POINT_HORIZONTAL); 
 606   m_canvas->AddShape(control); 
 607   m_controlPoints.Append(control); 
 611 void wxPolygonShape::ResetControlPoints() 
 613   wxNode 
*node 
= m_points
->First(); 
 614   wxNode 
*controlPointNode 
= m_controlPoints
.First(); 
 615   while (node 
&& controlPointNode
) 
 617     wxRealPoint 
*point 
= (wxRealPoint 
*)node
->Data(); 
 618     wxPolygonControlPoint 
*controlPoint 
= (wxPolygonControlPoint 
*)controlPointNode
->Data(); 
 620     controlPoint
->m_xoffset 
= point
->x
; 
 621     controlPoint
->m_yoffset 
= point
->y
; 
 622     controlPoint
->m_polygonVertex 
= point
; 
 625     controlPointNode 
= controlPointNode
->Next(); 
 629   if (m_controlPoints.Number() < 1) 
 632   float maxX, maxY, minX, minY; 
 634   GetBoundingBoxMax(&maxX, &maxY); 
 635   GetBoundingBoxMin(&minX, &minY); 
 637   float widthMin = (float)(minX + CONTROL_POINT_SIZE + 2); 
 638   float heightMin = (float)(minY + CONTROL_POINT_SIZE + 2); 
 640   // Offsets from main object 
 641   float top = (float)(- (heightMin / 2.0)); 
 642   float bottom = (float)(heightMin / 2.0 + (maxY - minY)); 
 643   float left = (float)(- (widthMin / 2.0)); 
 644   float right = (float)(widthMin / 2.0 + (maxX - minX)); 
 646   wxNode *node = m_controlPoints.First(); 
 647   wxControlPoint *control = (wxControlPoint *)node->Data(); 
 648   control->xoffset = left; control->yoffset = top; 
 650   node = node->Next(); control = (wxControlPoint *)node->Data(); 
 651   control->xoffset = 0; control->yoffset = top; 
 653   node = node->Next(); control = (wxControlPoint *)node->Data(); 
 654   control->xoffset = right; control->yoffset = top; 
 656   node = node->Next(); control = (wxControlPoint *)node->Data(); 
 657   control->xoffset = right; control->yoffset = 0; 
 659   node = node->Next(); control = (wxControlPoint *)node->Data(); 
 660   control->xoffset = right; control->yoffset = bottom; 
 662   node = node->Next(); control = (wxControlPoint *)node->Data(); 
 663   control->xoffset = 0; control->yoffset = bottom; 
 665   node = node->Next(); control = (wxControlPoint *)node->Data(); 
 666   control->xoffset = left; control->yoffset = bottom; 
 668   node = node->Next(); control = (wxControlPoint *)node->Data(); 
 669   control->xoffset = left; control->yoffset = 0; 
 675 void wxPolygonShape::WritePrologAttributes(wxExpr 
*clause
) 
 677   wxShape::WritePrologAttributes(clause
); 
 679   clause
->AddAttributeValue("x", m_xpos
); 
 680   clause
->AddAttributeValue("y", m_ypos
); 
 682   // Make a list of lists for the coordinates 
 683   wxExpr 
*list 
= new wxExpr(PrologList
); 
 684   wxNode 
*node 
= m_points
->First(); 
 687     wxRealPoint 
*point 
= (wxRealPoint 
*)node
->Data(); 
 688     wxExpr 
*point_list 
= new wxExpr(PrologList
); 
 689     wxExpr 
*x_expr 
= new wxExpr((float)point
->x
); 
 690     wxExpr 
*y_expr 
= new wxExpr((float)point
->y
); 
 692     point_list
->Append(x_expr
); 
 693     point_list
->Append(y_expr
); 
 694     list
->Append(point_list
); 
 698   clause
->AddAttributeValue("points", list
); 
 700   // Save the original (unscaled) points 
 701   list 
= new wxExpr(PrologList
); 
 702   node 
= m_originalPoints
->First(); 
 705     wxRealPoint 
*point 
= (wxRealPoint 
*)node
->Data(); 
 706     wxExpr 
*point_list 
= new wxExpr(PrologList
); 
 707     wxExpr 
*x_expr 
= new wxExpr((float) point
->x
); 
 708     wxExpr 
*y_expr 
= new wxExpr((float) point
->y
); 
 709     point_list
->Append(x_expr
); 
 710     point_list
->Append(y_expr
); 
 711     list
->Append(point_list
); 
 715   clause
->AddAttributeValue("m_originalPoints", list
); 
 718 void wxPolygonShape::ReadPrologAttributes(wxExpr 
*clause
) 
 720   wxShape::ReadPrologAttributes(clause
); 
 722   // Read a list of lists 
 723   m_points 
= new wxList
; 
 724   m_originalPoints 
= new wxList
; 
 726   wxExpr 
*points_list 
= NULL
; 
 727   clause
->AssignAttributeValue("points", &points_list
); 
 729   // If no points_list, don't crash!! Assume a diamond instead. 
 730   float the_height 
= 100.0; 
 731   float the_width 
= 100.0; 
 734     wxRealPoint 
*point 
= new wxRealPoint(0.0, (-the_height
/2)); 
 735     m_points
->Append((wxObject
*) point
); 
 737     point 
= new wxRealPoint((the_width
/2), 0.0); 
 738     m_points
->Append((wxObject
*) point
); 
 740     point 
= new wxRealPoint(0.0, (the_height
/2)); 
 741     m_points
->Append((wxObject
*) point
); 
 743     point 
= new wxRealPoint((-the_width
/2), 0.0); 
 744     m_points
->Append((wxObject
*) point
); 
 746     point 
= new wxRealPoint(0.0, (-the_height
/2)); 
 747     m_points
->Append((wxObject
*) point
); 
 751     wxExpr 
*node 
= points_list
->value
.first
; 
 755       wxExpr 
*xexpr 
= node
->value
.first
; 
 756       long x 
= xexpr
->IntegerValue(); 
 758       wxExpr 
*yexpr 
= xexpr
->next
; 
 759       long y 
= yexpr
->IntegerValue(); 
 761       wxRealPoint 
*point 
= new wxRealPoint((float)x
, (float)y
); 
 762       m_points
->Append((wxObject
*) point
); 
 769   clause
->AssignAttributeValue("m_originalPoints", &points_list
); 
 771   // If no points_list, don't crash!! Assume a diamond instead. 
 774     wxRealPoint 
*point 
= new wxRealPoint(0.0, (-the_height
/2)); 
 775     m_originalPoints
->Append((wxObject
*) point
); 
 777     point 
= new wxRealPoint((the_width
/2), 0.0); 
 778     m_originalPoints
->Append((wxObject
*) point
); 
 780     point 
= new wxRealPoint(0.0, (the_height
/2)); 
 781     m_originalPoints
->Append((wxObject
*) point
); 
 783     point 
= new wxRealPoint((-the_width
/2), 0.0); 
 784     m_originalPoints
->Append((wxObject
*) point
); 
 786     point 
= new wxRealPoint(0.0, (-the_height
/2)); 
 787     m_originalPoints
->Append((wxObject
*) point
); 
 789     m_originalWidth 
= the_width
; 
 790     m_originalHeight 
= the_height
; 
 794     wxExpr 
*node 
= points_list
->value
.first
; 
 801       wxExpr 
*xexpr 
= node
->value
.first
; 
 802       long x 
= xexpr
->IntegerValue(); 
 804       wxExpr 
*yexpr 
= xexpr
->next
; 
 805       long y 
= yexpr
->IntegerValue(); 
 807       wxRealPoint 
*point 
= new wxRealPoint((float)x
, (float)y
); 
 808       m_originalPoints
->Append((wxObject
*) point
); 
 821     m_originalWidth 
= max_x 
- min_x
; 
 822     m_originalHeight 
= max_y 
- min_y
; 
 825   CalculateBoundingBox(); 
 829 void wxPolygonShape::Copy(wxShape
& copy
) 
 833   wxASSERT( copy
.IsKindOf(CLASSINFO(wxPolygonShape
)) ); 
 835   wxPolygonShape
& polyCopy 
= (wxPolygonShape
&) copy
; 
 837   if (polyCopy
.m_points
) 
 838     delete polyCopy
.m_points
; 
 840   polyCopy
.m_points 
= new wxList
; 
 842   if (polyCopy
.m_originalPoints
) 
 843     delete polyCopy
.m_originalPoints
; 
 845   polyCopy
.m_originalPoints 
= new wxList
; 
 847   wxNode 
*node 
= m_points
->First(); 
 850     wxRealPoint 
*point 
= (wxRealPoint 
*)node
->Data(); 
 851     wxRealPoint 
*new_point 
= new wxRealPoint(point
->x
, point
->y
); 
 852     polyCopy
.m_points
->Append((wxObject
*) new_point
); 
 855   node 
= m_originalPoints
->First(); 
 858     wxRealPoint 
*point 
= (wxRealPoint 
*)node
->Data(); 
 859     wxRealPoint 
*new_point 
= new wxRealPoint(point
->x
, point
->y
); 
 860     polyCopy
.m_originalPoints
->Append((wxObject
*) new_point
); 
 863   polyCopy
.m_boundWidth 
= m_boundWidth
; 
 864   polyCopy
.m_boundHeight 
= m_boundHeight
; 
 865   polyCopy
.m_originalWidth 
= m_originalWidth
; 
 866   polyCopy
.m_originalHeight 
= m_originalHeight
; 
 869 int wxPolygonShape::GetNumberOfAttachments() 
 871   int maxN 
= (m_points 
? (m_points
->Number() - 1) : 0); 
 872   wxNode 
*node 
= m_attachmentPoints
.First(); 
 875     wxAttachmentPoint 
*point 
= (wxAttachmentPoint 
*)node
->Data(); 
 876     if (point
->m_id 
> maxN
) 
 883 bool wxPolygonShape::GetAttachmentPosition(int attachment
, float *x
, float *y
, 
 884                                          int nth
, int no_arcs
, wxLineShape 
*line
) 
 886   if (m_attachmentMode 
&& m_points 
&& attachment 
< m_points
->Number()) 
 888     wxRealPoint 
*point 
= (wxRealPoint 
*)m_points
->Nth(attachment
)->Data(); 
 889     *x 
= point
->x 
+ m_xpos
; 
 890     *y 
= point
->y 
+ m_ypos
; 
 894   { return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
); } 
 897 bool wxPolygonShape::AttachmentIsValid(int attachment
) 
 902   if ((attachment 
>= 0) && (attachment 
< m_points
->Number())) 
 905   wxNode 
*node 
= m_attachmentPoints
.First(); 
 908     wxAttachmentPoint 
*point 
= (wxAttachmentPoint 
*)node
->Data(); 
 909     if (point
->m_id 
== attachment
) 
 918 IMPLEMENT_DYNAMIC_CLASS(wxRectangleShape
, wxShape
) 
 920 wxRectangleShape::wxRectangleShape(float w
, float h
) 
 922   m_width 
= w
; m_height 
= h
; m_cornerRadius 
= 0.0; 
 923   SetDefaultRegionSize(); 
 926 void wxRectangleShape::OnDraw(wxDC
& dc
) 
 928     float x1 
= (float)(m_xpos 
- m_width
/2.0); 
 929     float y1 
= (float)(m_ypos 
- m_height
/2.0); 
 931     if (m_shadowMode 
!= SHADOW_NONE
) 
 934         dc
.SetBrush(m_shadowBrush
); 
 935       dc
.SetPen(transparent_pen
); 
 937       if (m_cornerRadius 
!= 0.0) 
 938         dc
.DrawRoundedRectangle(x1 
+ m_shadowOffsetX
, y1 
+ m_shadowOffsetY
, 
 939                                  m_width
, m_height
, m_cornerRadius
); 
 941         dc
.DrawRectangle(x1 
+ m_shadowOffsetX
, y1 
+ m_shadowOffsetY
, m_width
, m_height
); 
 946       if (m_pen
->GetWidth() == 0) 
 947         dc
.SetPen(transparent_pen
); 
 952       dc
.SetBrush(m_brush
); 
 954     if (m_cornerRadius 
!= 0.0) 
 955       dc
.DrawRoundedRectangle(x1
, y1
, m_width
, m_height
, m_cornerRadius
); 
 957       dc
.DrawRectangle(x1
, y1
, m_width
, m_height
); 
 960 void wxRectangleShape::GetBoundingBoxMin(float *the_width
, float *the_height
) 
 962   *the_width 
= m_width
; 
 963   *the_height 
= m_height
; 
 966 void wxRectangleShape::SetSize(float x
, float y
, bool recursive
) 
 968   SetAttachmentSize(x
, y
); 
 969   m_width 
= (float)wxMax(x
, 1.0); 
 970   m_height 
= (float)wxMax(y
, 1.0); 
 971   SetDefaultRegionSize(); 
 974 void wxRectangleShape::SetCornerRadius(float rad
) 
 976   m_cornerRadius 
= rad
; 
 979 // Assume (x1, y1) is centre of box (most generally, line end at box) 
 980 bool wxRectangleShape::GetPerimeterPoint(float x1
, float y1
, 
 982                                      float *x3
, float *y3
) 
 984   float bound_x
, bound_y
; 
 985   GetBoundingBoxMax(&bound_x
, &bound_y
); 
 986   find_end_for_box(bound_x
, bound_y
, m_xpos
, m_ypos
, x2
, y2
, x3
, y3
); 
 992 void wxRectangleShape::WritePrologAttributes(wxExpr 
*clause
) 
 994   wxShape::WritePrologAttributes(clause
); 
 995   clause
->AddAttributeValue("x", m_xpos
); 
 996   clause
->AddAttributeValue("y", m_ypos
); 
 998   clause
->AddAttributeValue("width", m_width
); 
 999   clause
->AddAttributeValue("height", m_height
); 
1000   if (m_cornerRadius 
!= 0.0) 
1001     clause
->AddAttributeValue("corner", m_cornerRadius
); 
1004 void wxRectangleShape::ReadPrologAttributes(wxExpr 
*clause
) 
1006   wxShape::ReadPrologAttributes(clause
); 
1007   clause
->AssignAttributeValue("width", &m_width
); 
1008   clause
->AssignAttributeValue("height", &m_height
); 
1009   clause
->AssignAttributeValue("corner", &m_cornerRadius
); 
1011   // In case we're reading an old file, set the region's size 
1012   if (m_regions
.Number() == 1) 
1014     wxShapeRegion 
*region 
= (wxShapeRegion 
*)m_regions
.First()->Data(); 
1015     region
->SetSize(m_width
, m_height
); 
1020 void wxRectangleShape::Copy(wxShape
& copy
) 
1022   wxShape::Copy(copy
); 
1024   wxASSERT( copy
.IsKindOf(CLASSINFO(wxRectangleShape
)) ); 
1026   wxRectangleShape
& rectCopy 
= (wxRectangleShape
&) copy
; 
1027   rectCopy
.m_width 
= m_width
; 
1028   rectCopy
.m_height 
= m_height
; 
1029   rectCopy
.m_cornerRadius 
= m_cornerRadius
; 
1032 int wxRectangleShape::GetNumberOfAttachments() 
1034   return wxShape::GetNumberOfAttachments(); 
1037 // There are 4 attachment points on a rectangle - 0 = top, 1 = right, 2 = bottom, 
1039 bool wxRectangleShape::GetAttachmentPosition(int attachment
, float *x
, float *y
, 
1040                                          int nth
, int no_arcs
, wxLineShape 
*line
) 
1042   if (m_attachmentMode
) 
1044     float top 
= (float)(m_ypos 
+ m_height
/2.0); 
1045     float bottom 
= (float)(m_ypos 
- m_height
/2.0); 
1046     float left 
= (float)(m_xpos 
- m_width
/2.0); 
1047     float right 
= (float)(m_xpos 
+ m_width
/2.0); 
1049     bool isEnd 
= (line 
&& line
->IsEnd(this)); 
1055         if (m_spaceAttachments
) 
1057           if (line 
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
)) 
1059             // Align line according to the next handle along 
1060             wxRealPoint 
*point 
= line
->GetNextControlPoint(this); 
1061             if (point
->x 
< left
) 
1063             else if (point
->x 
> right
) 
1069             *x 
= left 
+ (nth 
+ 1)*m_width
/(no_arcs 
+ 1); 
1079         if (m_spaceAttachments
) 
1081           if (line 
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
)) 
1083             // Align line according to the next handle along 
1084             wxRealPoint 
*point 
= line
->GetNextControlPoint(this); 
1085             if (point
->y 
< bottom
) 
1087             else if (point
->y 
> top
) 
1093             *y 
= bottom 
+ (nth 
+ 1)*m_height
/(no_arcs 
+ 1); 
1100         if (m_spaceAttachments
) 
1102           if (line 
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
)) 
1104             // Align line according to the next handle along 
1105             wxRealPoint 
*point 
= line
->GetNextControlPoint(this); 
1106             if (point
->x 
< left
) 
1108             else if (point
->x 
> right
) 
1114             *x 
= left 
+ (nth 
+ 1)*m_width
/(no_arcs 
+ 1); 
1123         if (m_spaceAttachments
) 
1125           if (line 
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
)) 
1127             // Align line according to the next handle along 
1128             wxRealPoint 
*point 
= line
->GetNextControlPoint(this); 
1129             if (point
->y 
< bottom
) 
1131             else if (point
->y 
> top
) 
1137             *y 
= bottom 
+ (nth 
+ 1)*m_height
/(no_arcs 
+ 1); 
1144         return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
); 
1151   { *x 
= m_xpos
; *y 
= m_ypos
; return TRUE
; } 
1154 // Text object (no box) 
1156 IMPLEMENT_DYNAMIC_CLASS(wxTextShape
, wxRectangleShape
) 
1158 wxTextShape::wxTextShape(float width
, float height
): 
1159   wxRectangleShape(width
, height
) 
1163 void wxTextShape::OnDraw(wxDC
& dc
) 
1167 void wxTextShape::Copy(wxShape
& copy
) 
1169   wxRectangleShape::Copy(copy
); 
1173 void wxTextShape::WritePrologAttributes(wxExpr 
*clause
) 
1175   wxRectangleShape::WritePrologAttributes(clause
); 
1181 IMPLEMENT_DYNAMIC_CLASS(wxEllipseShape
, wxShape
) 
1183 wxEllipseShape::wxEllipseShape(float w
, float h
) 
1185   m_width 
= w
; m_height 
= h
; 
1186   SetDefaultRegionSize(); 
1189 void wxEllipseShape::GetBoundingBoxMin(float *w
, float *h
) 
1191   *w 
= m_width
; *h 
= m_height
; 
1194 bool wxEllipseShape::GetPerimeterPoint(float x1
, float y1
, 
1196                                       float *x3
, float *y3
) 
1198   float bound_x
, bound_y
; 
1199   GetBoundingBoxMax(&bound_x
, &bound_y
); 
1201 //  find_end_for_box(bound_x, bound_y, m_xpos, m_ypos, x2, y2, x3, y3); 
1202   draw_arc_to_ellipse(m_xpos
, m_ypos
, bound_x
, bound_y
, x2
, y2
, x1
, y1
, x3
, y3
); 
1207 void wxEllipseShape::OnDraw(wxDC
& dc
) 
1209     if (m_shadowMode 
!= SHADOW_NONE
) 
1212         dc
.SetBrush(m_shadowBrush
); 
1213       dc
.SetPen(transparent_pen
); 
1214       dc
.DrawEllipse((m_xpos 
- GetWidth()/2) + m_shadowOffsetX
, 
1215                       (m_ypos 
- GetHeight()/2) + m_shadowOffsetY
, 
1216                       GetWidth(), GetHeight()); 
1221       if (m_pen
->GetWidth() == 0) 
1222         dc
.SetPen(transparent_pen
); 
1227       dc
.SetBrush(m_brush
); 
1228     dc
.DrawEllipse((m_xpos 
- GetWidth()/2), (m_ypos 
- GetHeight()/2), GetWidth(), GetHeight()); 
1231 void wxEllipseShape::SetSize(float x
, float y
, bool recursive
) 
1233   SetAttachmentSize(x
, y
); 
1236   SetDefaultRegionSize(); 
1240 void wxEllipseShape::WritePrologAttributes(wxExpr 
*clause
) 
1242   wxShape::WritePrologAttributes(clause
); 
1243   clause
->AddAttributeValue("x", m_xpos
); 
1244   clause
->AddAttributeValue("y", m_ypos
); 
1246   clause
->AddAttributeValue("width", m_width
); 
1247   clause
->AddAttributeValue("height", m_height
); 
1250 void wxEllipseShape::ReadPrologAttributes(wxExpr 
*clause
) 
1252   wxShape::ReadPrologAttributes(clause
); 
1253   clause
->AssignAttributeValue("width", &m_width
); 
1254   clause
->AssignAttributeValue("height", &m_height
); 
1256   // In case we're reading an old file, set the region's size 
1257   if (m_regions
.Number() == 1) 
1259     wxShapeRegion 
*region 
= (wxShapeRegion 
*)m_regions
.First()->Data(); 
1260     region
->SetSize(m_width
, m_height
); 
1265 void wxEllipseShape::Copy(wxShape
& copy
) 
1267   wxShape::Copy(copy
); 
1269   wxASSERT( copy
.IsKindOf(CLASSINFO(wxEllipseShape
)) ); 
1271   wxEllipseShape
& ellipseCopy 
= (wxEllipseShape
&) copy
; 
1273   ellipseCopy
.m_width 
= m_width
; 
1274   ellipseCopy
.m_height 
= m_height
; 
1277 int wxEllipseShape::GetNumberOfAttachments() 
1279   return wxShape::GetNumberOfAttachments(); 
1282 // There are 4 attachment points on an ellipse - 0 = top, 1 = right, 2 = bottom, 
1284 bool wxEllipseShape::GetAttachmentPosition(int attachment
, float *x
, float *y
, 
1285                                          int nth
, int no_arcs
, wxLineShape 
*line
) 
1287   if (m_attachmentMode
) 
1289     float top 
= (float)(m_ypos 
+ m_height
/2.0); 
1290     float bottom 
= (float)(m_ypos 
- m_height
/2.0); 
1291     float left 
= (float)(m_xpos 
- m_width
/2.0); 
1292     float right 
= (float)(m_xpos 
+ m_width
/2.0); 
1297         if (m_spaceAttachments
) 
1298           *x 
= left 
+ (nth 
+ 1)*m_width
/(no_arcs 
+ 1); 
1301         // We now have the point on the bounding box: but get the point on the ellipse 
1302         // by imagining a vertical line from (*x, m_ypos - m_height- 500) to (*x, m_ypos) intersecting 
1304         draw_arc_to_ellipse(m_xpos
, m_ypos
, m_width
, m_height
, *x
, (float)(m_ypos
-m_height
-500), *x
, m_ypos
, x
, y
); 
1310         if (m_spaceAttachments
) 
1311           *y 
= bottom 
+ (nth 
+ 1)*m_height
/(no_arcs 
+ 1); 
1313         draw_arc_to_ellipse(m_xpos
, m_ypos
, m_width
, m_height
, (float)(m_xpos
+m_width
+500), *y
, m_xpos
, *y
, x
, y
); 
1318         if (m_spaceAttachments
) 
1319           *x 
= left 
+ (nth 
+ 1)*m_width
/(no_arcs 
+ 1); 
1322         draw_arc_to_ellipse(m_xpos
, m_ypos
, m_width
, m_height
, *x
, (float)(m_ypos
+m_height
+500), *x
, m_ypos
, x
, y
); 
1328         if (m_spaceAttachments
) 
1329           *y 
= bottom 
+ (nth 
+ 1)*m_height
/(no_arcs 
+ 1); 
1331         draw_arc_to_ellipse(m_xpos
, m_ypos
, m_width
, m_height
, (float)(m_xpos
-m_width
-500), *y
, m_xpos
, *y
, x
, y
); 
1336         return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
); 
1343   { *x 
= m_xpos
; *y 
= m_ypos
; return TRUE
; } 
1348 IMPLEMENT_DYNAMIC_CLASS(wxCircleShape
, wxEllipseShape
) 
1350 wxCircleShape::wxCircleShape(float diameter
):wxEllipseShape(diameter
, diameter
) 
1354 void wxCircleShape::Copy(wxShape
& copy
) 
1356   wxEllipseShape::Copy(copy
); 
1359 bool wxCircleShape::GetPerimeterPoint(float x1
, float y1
, 
1361                                       float *x3
, float *y3
) 
1363   find_end_for_circle(m_width
/2,  
1364                       m_xpos
, m_ypos
,  // Centre of circle 
1365                       x2
, y2
,  // Other end of line 
1373 float wxControlPoint::controlPointDragStartX 
= 0.0; 
1374 float wxControlPoint::controlPointDragStartY 
= 0.0; 
1375 float wxControlPoint::controlPointDragStartWidth 
= 0.0; 
1376 float wxControlPoint::controlPointDragStartHeight 
= 0.0; 
1377 float wxControlPoint::controlPointDragEndWidth 
= 0.0; 
1378 float wxControlPoint::controlPointDragEndHeight 
= 0.0; 
1379 float wxControlPoint::controlPointDragPosX 
= 0.0; 
1380 float wxControlPoint::controlPointDragPosY 
= 0.0; 
1382 IMPLEMENT_DYNAMIC_CLASS(wxControlPoint
, wxRectangleShape
) 
1384 wxControlPoint::wxControlPoint(wxShapeCanvas 
*theCanvas
, wxShape 
*object
, float size
, float the_xoffset
, float the_yoffset
, int the_type
):wxRectangleShape(size
, size
) 
1386   m_canvas 
= theCanvas
; 
1388   m_xoffset 
= the_xoffset
; 
1389   m_yoffset 
= the_yoffset
; 
1391   SetPen(black_foreground_pen
); 
1392   SetBrush(wxBLACK_BRUSH
); 
1395   m_eraseObject 
= TRUE
; 
1398 wxControlPoint::~wxControlPoint() 
1402 // Don't even attempt to draw any text - waste of time! 
1403 void wxControlPoint::OnDrawContents(wxDC
& dc
) 
1407 void wxControlPoint::OnDraw(wxDC
& dc
) 
1409   m_xpos 
= m_shape
->GetX() + m_xoffset
; 
1410   m_ypos 
= m_shape
->GetY() + m_yoffset
; 
1411   wxRectangleShape::OnDraw(dc
); 
1414 void wxControlPoint::OnErase(wxDC
& dc
) 
1416   wxRectangleShape::OnErase(dc
); 
1419 // Implement resizing of canvas object 
1420 void wxControlPoint::OnDragLeft(bool draw
, float x
, float y
, int keys
, int attachment
) 
1422     m_shape
->GetEventHandler()->OnSizingDragLeft(this, draw
, x
, y
, keys
, attachment
); 
1425 void wxControlPoint::OnBeginDragLeft(float x
, float y
, int keys
, int attachment
) 
1427     m_shape
->GetEventHandler()->OnSizingBeginDragLeft(this, x
, y
, keys
, attachment
); 
1430 void wxControlPoint::OnEndDragLeft(float x
, float y
, int keys
, int attachment
) 
1432     m_shape
->GetEventHandler()->OnSizingEndDragLeft(this, x
, y
, keys
, attachment
); 
1435 int wxControlPoint::GetNumberOfAttachments() 
1440 bool wxControlPoint::GetAttachmentPosition(int attachment
, float *x
, float *y
, 
1441                                          int nth
, int no_arcs
, wxLineShape 
*line
) 
1443   *x 
= m_xpos
; *y 
= m_ypos
; 
1447 // Control points ('handles') redirect control to the actual shape, to make it easier 
1448 // to override sizing behaviour. 
1449 void wxShape::OnSizingDragLeft(wxControlPoint
* pt
, bool draw
, float x
, float y
, int keys
, int attachment
) 
1453   this->GetBoundingBoxMin(&bound_x
, &bound_y
); 
1455   wxClientDC 
dc(GetCanvas()); 
1456   GetCanvas()->PrepareDC(dc
); 
1458   dc
.SetLogicalFunction(wxXOR
); 
1460   wxPen 
dottedPen(wxColour(0, 0, 0), 1, wxDOT
); 
1461   dc
.SetPen(dottedPen
); 
1462   dc
.SetBrush((* wxTRANSPARENT_BRUSH
)); 
1464   if (this->GetCentreResize()) 
1466     // Maintain the same centre point. 
1467     float new_width 
= (float)(2.0*fabs(x 
- this->GetX())); 
1468     float new_height 
= (float)(2.0*fabs(y 
- this->GetY())); 
1470     // Constrain sizing according to what control point you're dragging 
1471     if (pt
->m_type 
== CONTROL_POINT_HORIZONTAL
) 
1472       new_height 
= bound_y
; 
1473     else if (pt
->m_type 
== CONTROL_POINT_VERTICAL
) 
1474       new_width 
= bound_x
; 
1475     else if (pt
->m_type 
== CONTROL_POINT_DIAGONAL 
&& (keys 
& KEY_SHIFT
)) 
1476       new_height 
= bound_y
*(new_width
/bound_x
); 
1478     if (this->GetFixedWidth()) 
1479       new_width 
= bound_x
; 
1481     if (this->GetFixedHeight()) 
1482       new_height 
= bound_y
; 
1484     pt
->controlPointDragEndWidth 
= new_width
; 
1485     pt
->controlPointDragEndHeight 
= new_height
; 
1487     this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(), 
1488                                 new_width
, new_height
); 
1492     // Don't maintain the same centre point! 
1493     float newX1 
= wxMin(pt
->controlPointDragStartX
, x
); 
1494     float newY1 
= wxMin(pt
->controlPointDragStartY
, y
); 
1495     float newX2 
= wxMax(pt
->controlPointDragStartX
, x
); 
1496     float newY2 
= wxMax(pt
->controlPointDragStartY
, y
); 
1497     if (pt
->m_type 
== CONTROL_POINT_HORIZONTAL
) 
1499       newY1 
= pt
->controlPointDragStartY
; 
1500       newY2 
= newY1 
+ pt
->controlPointDragStartHeight
; 
1502     else if (pt
->m_type 
== CONTROL_POINT_VERTICAL
) 
1504       newX1 
= pt
->controlPointDragStartX
; 
1505       newX2 
= newX1 
+ pt
->controlPointDragStartWidth
; 
1507     else if (pt
->m_type 
== CONTROL_POINT_DIAGONAL 
&& (keys 
& KEY_SHIFT
)) 
1509       float newH 
= (float)((newX2 
- newX1
)*(pt
->controlPointDragStartHeight
/pt
->controlPointDragStartWidth
)); 
1510       if (GetY() > pt
->controlPointDragStartY
) 
1511         newY2 
= (float)(newY1 
+ newH
); 
1513         newY1 
= (float)(newY2 
- newH
); 
1515     float newWidth 
= (float)(newX2 
- newX1
); 
1516     float newHeight 
= (float)(newY2 
- newY1
); 
1518     pt
->controlPointDragPosX 
= (float)(newX1 
+ (newWidth
/2.0)); 
1519     pt
->controlPointDragPosY 
= (float)(newY1 
+ (newHeight
/2.0)); 
1520     if (this->GetFixedWidth()) 
1523     if (this->GetFixedHeight()) 
1524       newHeight 
= bound_y
; 
1526     pt
->controlPointDragEndWidth 
= newWidth
; 
1527     pt
->controlPointDragEndHeight 
= newHeight
; 
1528     this->GetEventHandler()->OnDrawOutline(dc
, pt
->controlPointDragPosX
, pt
->controlPointDragPosY
, newWidth
, newHeight
); 
1532 void wxShape::OnSizingBeginDragLeft(wxControlPoint
* pt
, float x
, float y
, int keys
, int attachment
) 
1534   m_canvas
->CaptureMouse(); 
1536   wxClientDC 
dc(GetCanvas()); 
1537   GetCanvas()->PrepareDC(dc
); 
1539   if (pt
->m_eraseObject
) 
1542   dc
.SetLogicalFunction(wxXOR
); 
1546   this->GetBoundingBoxMin(&bound_x
, &bound_y
); 
1548   // Choose the 'opposite corner' of the object as the stationary 
1549   // point in case this is non-centring resizing. 
1550   if (pt
->GetX() < this->GetX()) 
1551     pt
->controlPointDragStartX 
= (float)(this->GetX() + (bound_x
/2.0)); 
1553     pt
->controlPointDragStartX 
= (float)(this->GetX() - (bound_x
/2.0)); 
1555   if (pt
->GetY() < this->GetY()) 
1556     pt
->controlPointDragStartY 
= (float)(this->GetY() + (bound_y
/2.0)); 
1558     pt
->controlPointDragStartY 
= (float)(this->GetY() - (bound_y
/2.0)); 
1560   if (pt
->m_type 
== CONTROL_POINT_HORIZONTAL
) 
1561     pt
->controlPointDragStartY 
= (float)(this->GetY() - (bound_y
/2.0)); 
1562   else if (pt
->m_type 
== CONTROL_POINT_VERTICAL
) 
1563     pt
->controlPointDragStartX 
= (float)(this->GetX() - (bound_x
/2.0)); 
1565   // We may require the old width and height. 
1566   pt
->controlPointDragStartWidth 
= bound_x
; 
1567   pt
->controlPointDragStartHeight 
= bound_y
; 
1569   wxPen 
dottedPen(wxColour(0, 0, 0), 1, wxDOT
); 
1570   dc
.SetPen(dottedPen
); 
1571   dc
.SetBrush((* wxTRANSPARENT_BRUSH
)); 
1573   if (this->GetCentreResize()) 
1575     float new_width 
= (float)(2.0*fabs(x 
- this->GetX())); 
1576     float new_height 
= (float)(2.0*fabs(y 
- this->GetY())); 
1578     // Constrain sizing according to what control point you're dragging 
1579     if (pt
->m_type 
== CONTROL_POINT_HORIZONTAL
) 
1580       new_height 
= bound_y
; 
1581     else if (pt
->m_type 
== CONTROL_POINT_VERTICAL
) 
1582       new_width 
= bound_x
; 
1583     else if (pt
->m_type 
== CONTROL_POINT_DIAGONAL 
&& (keys 
& KEY_SHIFT
)) 
1584       new_height 
= bound_y
*(new_width
/bound_x
); 
1586     if (this->GetFixedWidth()) 
1587       new_width 
= bound_x
; 
1589     if (this->GetFixedHeight()) 
1590       new_height 
= bound_y
; 
1592     pt
->controlPointDragEndWidth 
= new_width
; 
1593     pt
->controlPointDragEndHeight 
= new_height
; 
1594     this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(), 
1595                                 new_width
, new_height
); 
1599     // Don't maintain the same centre point! 
1600     float newX1 
= wxMin(pt
->controlPointDragStartX
, x
); 
1601     float newY1 
= wxMin(pt
->controlPointDragStartY
, y
); 
1602     float newX2 
= wxMax(pt
->controlPointDragStartX
, x
); 
1603     float newY2 
= wxMax(pt
->controlPointDragStartY
, y
); 
1604     if (pt
->m_type 
== CONTROL_POINT_HORIZONTAL
) 
1606       newY1 
= pt
->controlPointDragStartY
; 
1607       newY2 
= newY1 
+ pt
->controlPointDragStartHeight
; 
1609     else if (pt
->m_type 
== CONTROL_POINT_VERTICAL
) 
1611       newX1 
= pt
->controlPointDragStartX
; 
1612       newX2 
= newX1 
+ pt
->controlPointDragStartWidth
; 
1614     else if (pt
->m_type 
== CONTROL_POINT_DIAGONAL 
&& (keys 
& KEY_SHIFT
)) 
1616       float newH 
= (float)((newX2 
- newX1
)*(pt
->controlPointDragStartHeight
/pt
->controlPointDragStartWidth
)); 
1617       if (pt
->GetY() > pt
->controlPointDragStartY
) 
1618         newY2 
= (float)(newY1 
+ newH
); 
1620         newY1 
= (float)(newY2 
- newH
); 
1622     float newWidth 
= (float)(newX2 
- newX1
); 
1623     float newHeight 
= (float)(newY2 
- newY1
); 
1625     pt
->controlPointDragPosX 
= (float)(newX1 
+ (newWidth
/2.0)); 
1626     pt
->controlPointDragPosY 
= (float)(newY1 
+ (newHeight
/2.0)); 
1627     if (this->GetFixedWidth()) 
1630     if (this->GetFixedHeight()) 
1631       newHeight 
= bound_y
; 
1633     pt
->controlPointDragEndWidth 
= newWidth
; 
1634     pt
->controlPointDragEndHeight 
= newHeight
; 
1635     this->GetEventHandler()->OnDrawOutline(dc
, pt
->controlPointDragPosX
, pt
->controlPointDragPosY
, newWidth
, newHeight
); 
1639 void wxShape::OnSizingEndDragLeft(wxControlPoint
* pt
, float x
, float y
, int keys
, int attachment
) 
1641   wxClientDC 
dc(GetCanvas()); 
1642   GetCanvas()->PrepareDC(dc
); 
1644   m_canvas
->ReleaseMouse(); 
1645   dc
.SetLogicalFunction(wxCOPY
); 
1647   this->ResetControlPoints(); 
1649   if (!pt
->m_eraseObject
) 
1652   this->SetSize(pt
->controlPointDragEndWidth
, pt
->controlPointDragEndHeight
); 
1654   // The next operation could destroy this control point (it does for label objects, 
1655   // via formatting the text), so save all values we're going to use, or 
1656   // we'll be accessing garbage. 
1657   wxShape 
*theObject 
= this; 
1658   wxShapeCanvas 
*theCanvas 
= m_canvas
; 
1659   bool eraseIt 
= pt
->m_eraseObject
; 
1661   if (theObject
->GetCentreResize()) 
1662     theObject
->Move(dc
, theObject
->GetX(), theObject
->GetY()); 
1664     theObject
->Move(dc
, pt
->controlPointDragPosX
, pt
->controlPointDragPosY
); 
1667     theObject
->Show(TRUE
); 
1669   // Recursively redraw links if we have a composite. 
1670   if (theObject
->GetChildren().Number() > 0) 
1671     theObject
->DrawLinks(dc
, -1, TRUE
); 
1673   float width
, height
; 
1674   theObject
->GetBoundingBoxMax(&width
, &height
); 
1675   theObject
->GetEventHandler()->OnEndSize(width
, height
); 
1677   if (!theCanvas
->GetQuickEditMode() && eraseIt
) theCanvas
->Redraw(dc
); 
1682 // Polygon control points 
1684 IMPLEMENT_DYNAMIC_CLASS(wxPolygonControlPoint
, wxControlPoint
) 
1686 wxPolygonControlPoint::wxPolygonControlPoint(wxShapeCanvas 
*theCanvas
, wxShape 
*object
, float size
, 
1687   wxRealPoint 
*vertex
, float the_xoffset
, float the_yoffset
): 
1688   wxControlPoint(theCanvas
, object
, size
, the_xoffset
, the_yoffset
, 0) 
1690   m_polygonVertex 
= vertex
; 
1691   m_originalDistance 
= 0.0; 
1694 wxPolygonControlPoint::~wxPolygonControlPoint() 
1698 // Implement resizing polygon or moving the vertex. 
1699 void wxPolygonControlPoint::OnDragLeft(bool draw
, float x
, float y
, int keys
, int attachment
) 
1701     m_shape
->GetEventHandler()->OnSizingDragLeft(this, draw
, x
, y
, keys
, attachment
); 
1704 void wxPolygonControlPoint::OnBeginDragLeft(float x
, float y
, int keys
, int attachment
) 
1706     m_shape
->GetEventHandler()->OnSizingBeginDragLeft(this, x
, y
, keys
, attachment
); 
1709 void wxPolygonControlPoint::OnEndDragLeft(float x
, float y
, int keys
, int attachment
) 
1711     m_shape
->GetEventHandler()->OnSizingEndDragLeft(this, x
, y
, keys
, attachment
); 
1714 // Control points ('handles') redirect control to the actual shape, to make it easier 
1715 // to override sizing behaviour. 
1716 void wxPolygonShape::OnSizingDragLeft(wxControlPoint
* pt
, bool draw
, float x
, float y
, int keys
, int attachment
) 
1718   wxPolygonControlPoint
* ppt 
= (wxPolygonControlPoint
*) pt
; 
1720   wxClientDC 
dc(GetCanvas()); 
1721   GetCanvas()->PrepareDC(dc
); 
1723   dc
.SetLogicalFunction(wxXOR
); 
1725   wxPen 
dottedPen(wxColour(0, 0, 0), 1, wxDOT
); 
1726   dc
.SetPen(dottedPen
); 
1727   dc
.SetBrush((* wxTRANSPARENT_BRUSH
)); 
1731   this->GetBoundingBoxMin(&bound_x
, &bound_y
); 
1733   float new_width = (float)(2.0*fabs(x - this->GetX())); 
1734   float new_height = (float)(2.0*fabs(y - this->GetY())); 
1736   float dist 
= (float)sqrt((x 
- this->GetX())*(x 
- this->GetX()) + 
1737                     (y 
- this->GetY())*(y 
- this->GetY())); 
1739   if (keys 
& KEY_CTRL
) 
1741     m_canvas
->Snap(&x
, &y
); 
1744     ppt
->m_polygonVertex
->x 
= x 
- this->GetX(); 
1745     ppt
->m_polygonVertex
->y 
= y 
- this->GetY(); 
1748     ((wxPolygonShape 
*)this)->CalculateBoundingBox(); 
1749     ((wxPolygonShape 
*)this)->CalculatePolygonCentre(); 
1753     float new_width 
= (float)(dist
/ppt
->m_originalDistance
)*ppt
->m_originalSize
.x
; 
1754     float new_height 
= (float)(dist
/ppt
->m_originalDistance
)*ppt
->m_originalSize
.y
; 
1756     // Non-recursive SetSize for speed 
1757     this->SetSize(new_width
, new_height
, FALSE
); 
1760   this->GetBoundingBoxMax(&w
, &h
); 
1761   this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(), w
, h
); 
1764 void wxPolygonShape::OnSizingBeginDragLeft(wxControlPoint
* pt
, float x
, float y
, int keys
, int attachment
) 
1766   wxPolygonControlPoint
* ppt 
= (wxPolygonControlPoint
*) pt
; 
1768   wxClientDC 
dc(GetCanvas()); 
1769   GetCanvas()->PrepareDC(dc
); 
1773   dc
.SetLogicalFunction(wxXOR
); 
1777   this->GetBoundingBoxMin(&bound_x
, &bound_y
); 
1779   float dist 
= (float)sqrt((x 
- this->GetX())*(x 
- this->GetX()) + 
1780                     (y 
- this->GetY())*(y 
- this->GetY())); 
1782   ppt
->m_originalDistance 
= dist
; 
1783   ppt
->m_originalSize
.x 
= bound_x
; 
1784   ppt
->m_originalSize
.y 
= bound_y
; 
1786   if (ppt
->m_originalDistance 
== 0.0) ppt
->m_originalDistance 
= (float) 0.0001; 
1788   wxPen 
dottedPen(wxColour(0, 0, 0), 1, wxDOT
); 
1789   dc
.SetPen(dottedPen
); 
1790   dc
.SetBrush((* wxTRANSPARENT_BRUSH
)); 
1792   if (keys 
& KEY_CTRL
) 
1794     m_canvas
->Snap(&x
, &y
); 
1797     ppt
->m_polygonVertex
->x 
= x 
- this->GetX(); 
1798     ppt
->m_polygonVertex
->y 
= y 
- this->GetY(); 
1801     ((wxPolygonShape 
*)this)->CalculateBoundingBox(); 
1802     ((wxPolygonShape 
*)this)->CalculatePolygonCentre(); 
1806     float new_width 
= (float)(dist
/ppt
->m_originalDistance
)*ppt
->m_originalSize
.x
; 
1807     float new_height 
= (float)(dist
/ppt
->m_originalDistance
)*ppt
->m_originalSize
.y
; 
1809     // Non-recursive SetSize for speed 
1810     this->SetSize(new_width
, new_height
, FALSE
); 
1814   this->GetBoundingBoxMax(&w
, &h
); 
1815   this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(), w
, h
); 
1817   m_canvas
->CaptureMouse(); 
1820 void wxPolygonShape::OnSizingEndDragLeft(wxControlPoint
* pt
, float x
, float y
, int keys
, int attachment
) 
1822   wxClientDC 
dc(GetCanvas()); 
1823   GetCanvas()->PrepareDC(dc
); 
1825   m_canvas
->ReleaseMouse(); 
1826   dc
.SetLogicalFunction(wxCOPY
); 
1828   // If we're changing shape, must reset the original points 
1829   if (keys 
& KEY_CTRL
) 
1831     ((wxPolygonShape 
*)this)->CalculateBoundingBox(); 
1832     ((wxPolygonShape 
*)this)->UpdateOriginalPoints(); 
1835   ((wxPolygonShape 
*)this)->CalculateBoundingBox(); 
1836   ((wxPolygonShape 
*)this)->CalculatePolygonCentre(); 
1839   this->ResetControlPoints(); 
1840   this->Move(dc
, this->GetX(), this->GetY()); 
1841   if (!m_canvas
->GetQuickEditMode()) m_canvas
->Redraw(dc
); 
1848 IMPLEMENT_DYNAMIC_CLASS(wxShapeRegion
, wxObject
) 
1850 wxShapeRegion::wxShapeRegion() 
1853   m_font 
= g_oglNormalFont
; 
1861   m_regionProportionX 
= -1.0; 
1862   m_regionProportionY 
= -1.0; 
1863   m_formatMode 
= FORMAT_CENTRE_HORIZ 
| FORMAT_CENTRE_VERT
; 
1865   m_textColour 
= "BLACK"; 
1866   m_penColour 
= "BLACK"; 
1867   m_penStyle 
= wxSOLID
; 
1868   m_actualColourObject 
= NULL
; 
1869   m_actualPenObject 
= NULL
; 
1872 wxShapeRegion::wxShapeRegion(wxShapeRegion
& region
) 
1874   m_regionText 
= region
.m_regionText
; 
1875   m_regionName 
= region
.m_regionName
; 
1876   m_textColour 
= region
.m_textColour
; 
1878   m_font 
= region
.m_font
; 
1879   m_minHeight 
= region
.m_minHeight
; 
1880   m_minWidth 
= region
.m_minWidth
; 
1881   m_width 
= region
.m_width
; 
1882   m_height 
= region
.m_height
; 
1886   m_regionProportionX 
= region
.m_regionProportionX
; 
1887   m_regionProportionY 
= region
.m_regionProportionY
; 
1888   m_formatMode 
= region
.m_formatMode
; 
1889   m_actualColourObject 
= NULL
; 
1890   m_actualPenObject 
= NULL
; 
1891   m_penStyle 
= region
.m_penStyle
; 
1892   m_penColour 
= region
.m_penColour
; 
1895   wxNode 
*node 
= region
.m_formattedText
.First(); 
1898     wxShapeTextLine 
*line 
= (wxShapeTextLine 
*)node
->Data(); 
1899     wxShapeTextLine 
*new_line 
= 
1900       new wxShapeTextLine(line
->GetX(), line
->GetY(), line
->GetText()); 
1901     m_formattedText
.Append(new_line
); 
1902     node 
= node
->Next(); 
1906 wxShapeRegion::~wxShapeRegion() 
1911 void wxShapeRegion::ClearText() 
1913   wxNode 
*node 
= m_formattedText
.First(); 
1916     wxShapeTextLine 
*line 
= (wxShapeTextLine 
*)node
->Data(); 
1917     wxNode 
*next 
= node
->Next(); 
1924 void wxShapeRegion::SetFont(wxFont 
*f
) 
1929 void wxShapeRegion::SetMinSize(float w
, float h
) 
1935 void wxShapeRegion::SetSize(float w
, float h
) 
1941 void wxShapeRegion::SetPosition(float xp
, float yp
) 
1947 void wxShapeRegion::SetProportions(float xp
, float yp
) 
1949   m_regionProportionX 
= xp
; 
1950   m_regionProportionY 
= yp
; 
1953 void wxShapeRegion::SetFormatMode(int mode
) 
1955   m_formatMode 
= mode
; 
1958 void wxShapeRegion::SetColour(const wxString
& col
) 
1961   m_actualColourObject 
= NULL
; 
1964 wxColour 
*wxShapeRegion::GetActualColourObject() 
1966   if (!m_actualColourObject
) 
1967     m_actualColourObject 
= wxTheColourDatabase
->FindColour(GetColour()); 
1968   if (!m_actualColourObject
) 
1969     m_actualColourObject 
= wxBLACK
; 
1970   return m_actualColourObject
; 
1973 void wxShapeRegion::SetPenColour(const wxString
& col
) 
1976   m_actualPenObject 
= NULL
; 
1979 // Returns NULL if the pen is invisible 
1980 // (different to pen being transparent; indicates that 
1981 // region boundary should not be drawn.) 
1982 wxPen 
*wxShapeRegion::GetActualPen() 
1984   if (m_actualPenObject
) 
1985     return m_actualPenObject
; 
1987   if (!m_penColour
) return NULL
; 
1988   if (m_penColour 
== "Invisible") 
1990   m_actualPenObject 
= wxThePenList
->FindOrCreatePen(m_penColour
, 1, m_penStyle
); 
1991   return m_actualPenObject
;