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
)
72 m_originalPoints
= the_points
;
74 // Duplicate the list of points
75 m_points
= new wxList
;
77 wxNode
*node
= the_points
->First();
80 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
81 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
82 m_points
->Append((wxObject
*) new_point
);
85 CalculateBoundingBox();
86 m_originalWidth
= m_boundWidth
;
87 m_originalHeight
= m_boundHeight
;
88 SetDefaultRegionSize();
91 wxPolygonShape::~wxPolygonShape()
96 void wxPolygonShape::ClearPoints()
100 wxNode
*node
= m_points
->First();
103 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
106 node
= m_points
->First();
111 if (m_originalPoints
)
113 wxNode
*node
= m_originalPoints
->First();
116 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
119 node
= m_originalPoints
->First();
121 delete m_originalPoints
;
122 m_originalPoints
= NULL
;
127 // Width and height. Centre of object is centre of box.
128 void wxPolygonShape::GetBoundingBoxMin(float *width
, float *height
)
130 *width
= m_boundWidth
;
131 *height
= m_boundHeight
;
134 void wxPolygonShape::CalculateBoundingBox()
136 // Calculate bounding box at construction (and presumably resize) time
138 float right
= -10000;
140 float bottom
= -10000;
142 wxNode
*node
= m_points
->First();
145 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
146 if (point
->x
< left
) left
= point
->x
;
147 if (point
->x
> right
) right
= point
->x
;
149 if (point
->y
< top
) top
= point
->y
;
150 if (point
->y
> bottom
) bottom
= point
->y
;
154 m_boundWidth
= right
- left
;
155 m_boundHeight
= bottom
- top
;
158 // Recalculates the centre of the polygon, and
159 // readjusts the point offsets accordingly.
160 // Necessary since the centre of the polygon
161 // is expected to be the real centre of the bounding
163 void wxPolygonShape::CalculatePolygonCentre()
166 float right
= -10000;
168 float bottom
= -10000;
170 wxNode
*node
= m_points
->First();
173 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
174 if (point
->x
< left
) left
= point
->x
;
175 if (point
->x
> right
) right
= point
->x
;
177 if (point
->y
< top
) top
= point
->y
;
178 if (point
->y
> bottom
) bottom
= point
->y
;
182 float bwidth
= right
- left
;
183 float bheight
= bottom
- top
;
185 float newCentreX
= (float)(left
+ (bwidth
/2.0));
186 float newCentreY
= (float)(top
+ (bheight
/2.0));
188 node
= m_points
->First();
191 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
192 point
->x
-= newCentreX
;
193 point
->y
-= newCentreY
;
196 m_xpos
+= newCentreX
;
197 m_ypos
+= newCentreY
;
200 bool PolylineHitTest(float n
, float xvec
[], float yvec
[],
201 float x1
, float y1
, float x2
, float y2
)
205 float lastx
= xvec
[0];
206 float lasty
= yvec
[0];
208 float min_ratio
= 1.0;
213 for (i
= 1; i
< n
; i
++)
215 check_line_intersection(x1
, y1
, x2
, y2
, lastx
, lasty
, xvec
[i
], yvec
[i
],
216 &line_ratio
, &other_ratio
);
217 if (line_ratio
!= 1.0)
219 // sprintf(buf, "Line ratio = %.2f, other ratio = %.2f\n", line_ratio, other_ratio);
220 // ClipsErrorFunction(buf);
224 if (line_ratio
< min_ratio
)
225 min_ratio
= line_ratio
;
228 // Do last (implicit) line if last and first floats are not identical
229 if (!(xvec
[0] == lastx
&& yvec
[0] == lasty
))
231 check_line_intersection(x1
, y1
, x2
, y2
, lastx
, lasty
, xvec
[0], yvec
[0],
232 &line_ratio
, &other_ratio
);
233 if (line_ratio
!= 1.0)
235 // sprintf(buf, "Line ratio = %.2f, other ratio = %.2f\n", line_ratio, other_ratio);
236 // ClipsErrorFunction(buf);
238 if (line_ratio
< min_ratio
)
239 min_ratio
= line_ratio
;
241 // ClipsErrorFunction("\n");
245 bool wxPolygonShape::HitTest(float x
, float y
, int *attachment
, float *distance
)
247 // Imagine four lines radiating from this point. If all of these lines hit the polygon,
248 // we're inside it, otherwise we're not. Obviously we'd need more radiating lines
249 // to be sure of correct results for very strange (concave) shapes.
254 endPointsY
[0] = (float)(y
- 1000.0);
256 endPointsX
[1] = (float)(x
+ 1000.0);
260 endPointsY
[2] = (float)(y
+ 1000.0);
262 endPointsX
[3] = (float)(x
- 1000.0);
265 // Store polygon points in an array
266 int np
= m_points
->Number();
267 float *xpoints
= new float[np
];
268 float *ypoints
= new float[np
];
269 wxNode
*node
= m_points
->First();
273 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
274 xpoints
[i
] = point
->x
+ m_xpos
;
275 ypoints
[i
] = point
->y
+ m_ypos
;
280 // We assume it's inside the polygon UNLESS one or more
281 // lines don't hit the outline.
282 bool isContained
= TRUE
;
285 for (i
= 0; i
< noPoints
; i
++)
287 if (!PolylineHitTest(np
, xpoints
, ypoints
, x
, y
, endPointsX
[i
], endPointsY
[i
]))
292 ClipsErrorFunction("It's a hit!\n");
294 ClipsErrorFunction("No hit.\n");
302 int nearest_attachment
= 0;
304 // If a hit, check the attachment points within the object.
305 int n
= GetNumberOfAttachments();
306 float nearest
= 999999.0;
308 for (i
= 0; i
< n
; i
++)
311 if (GetAttachmentPosition(i
, &xp
, &yp
))
313 float l
= (float)sqrt(((xp
- x
) * (xp
- x
)) +
314 ((yp
- y
) * (yp
- y
)));
318 nearest_attachment
= i
;
322 *attachment
= nearest_attachment
;
327 // Really need to be able to reset the shape! Otherwise, if the
328 // points ever go to zero, we've lost it, and can't resize.
329 void wxPolygonShape::SetSize(float new_width
, float new_height
, bool recursive
)
331 SetAttachmentSize(new_width
, new_height
);
333 // Multiply all points by proportion of new size to old size
334 float x_proportion
= (float)(fabs(new_width
/m_originalWidth
));
335 float y_proportion
= (float)(fabs(new_height
/m_originalHeight
));
337 wxNode
*node
= m_points
->First();
338 wxNode
*original_node
= m_originalPoints
->First();
339 while (node
&& original_node
)
341 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
342 wxRealPoint
*original_point
= (wxRealPoint
*)original_node
->Data();
344 point
->x
= (original_point
->x
* x_proportion
);
345 point
->y
= (original_point
->y
* y_proportion
);
348 original_node
= original_node
->Next();
351 // CalculateBoundingBox();
352 m_boundWidth
= (float)fabs(new_width
);
353 m_boundHeight
= (float)fabs(new_height
);
354 SetDefaultRegionSize();
357 // Make the original points the same as the working points
358 void wxPolygonShape::UpdateOriginalPoints()
360 if (!m_originalPoints
) m_originalPoints
= new wxList
;
361 wxNode
*original_node
= m_originalPoints
->First();
362 while (original_node
)
364 wxNode
*next_node
= original_node
->Next();
365 wxRealPoint
*original_point
= (wxRealPoint
*)original_node
->Data();
366 delete original_point
;
367 delete original_node
;
369 original_node
= next_node
;
372 wxNode
*node
= m_points
->First();
375 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
376 wxRealPoint
*original_point
= new wxRealPoint(point
->x
, point
->y
);
377 m_originalPoints
->Append((wxObject
*) original_point
);
381 CalculateBoundingBox();
382 m_originalWidth
= m_boundWidth
;
383 m_originalHeight
= m_boundHeight
;
386 void wxPolygonShape::AddPolygonPoint(int pos
)
388 wxNode
*node
= m_points
->Nth(pos
);
389 if (!node
) node
= m_points
->First();
390 wxRealPoint
*firstPoint
= (wxRealPoint
*)node
->Data();
392 wxNode
*node2
= m_points
->Nth(pos
+ 1);
393 if (!node2
) node2
= m_points
->First();
394 wxRealPoint
*secondPoint
= (wxRealPoint
*)node2
->Data();
396 float x
= (float)((secondPoint
->x
- firstPoint
->x
)/2.0 + firstPoint
->x
);
397 float y
= (float)((secondPoint
->y
- firstPoint
->y
)/2.0 + firstPoint
->y
);
398 wxRealPoint
*point
= new wxRealPoint(x
, y
);
400 if (pos
>= (m_points
->Number() - 1))
401 m_points
->Append((wxObject
*) point
);
403 m_points
->Insert(node2
, (wxObject
*) point
);
405 UpdateOriginalPoints();
409 DeleteControlPoints();
414 void wxPolygonShape::DeletePolygonPoint(int pos
)
416 wxNode
*node
= m_points
->Nth(pos
);
419 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
422 UpdateOriginalPoints();
425 DeleteControlPoints();
431 // Assume (x1, y1) is centre of box (most generally, line end at box)
432 bool wxPolygonShape::GetPerimeterPoint(float x1
, float y1
,
434 float *x3
, float *y3
)
436 int n
= m_points
->Number();
438 // First check for situation where the line is vertical,
439 // and we would want to connect to a point on that vertical --
440 // find_end_for_polyline can't cope with this (the arrow
441 // gets drawn to the wrong place).
442 if ((!m_attachmentMode
) && (x1
== x2
))
444 // Look for the point we'd be connecting to. This is
446 wxNode
*node
= m_points
->First();
449 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
452 if ((y2
> y1
) && (point
->y
> 0.0))
454 *x3
= point
->x
+ m_xpos
;
455 *y3
= point
->y
+ m_ypos
;
458 else if ((y2
< y1
) && (point
->y
< 0.0))
460 *x3
= point
->x
+ m_xpos
;
461 *y3
= point
->y
+ m_ypos
;
469 float *xpoints
= new float[n
];
470 float *ypoints
= new float[n
];
472 wxNode
*node
= m_points
->First();
476 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
477 xpoints
[i
] = point
->x
+ m_xpos
;
478 ypoints
[i
] = point
->y
+ m_ypos
;
483 wxRealPoint *point = (wxRealPoint *)m_points->First()->Data();
484 xpoints[i] = point->x + m_xpos;
485 ypoints[i] = point->y + m_ypos;
488 find_end_for_polyline(n
, xpoints
, ypoints
,
489 x1
, y1
, x2
, y2
, x3
, y3
);
497 void wxPolygonShape::OnDraw(wxDC
& dc
)
499 int n
= m_points
->Number();
500 wxPoint
*intPoints
= new wxPoint
[n
];
502 for (i
= 0; i
< n
; i
++)
504 wxRealPoint
* point
= (wxRealPoint
*) m_points
->Nth(i
)->Data();
505 intPoints
[i
].x
= (int) point
->x
;
506 intPoints
[i
].y
= (int) point
->y
;
509 if (m_shadowMode
!= SHADOW_NONE
)
512 dc
.SetBrush(m_shadowBrush
);
513 dc
.SetPen(transparent_pen
);
515 dc
.DrawPolygon(n
, intPoints
, m_xpos
+ m_shadowOffsetX
, m_ypos
+ m_shadowOffsetY
);
520 if (m_pen
->GetWidth() == 0)
521 dc
.SetPen(transparent_pen
);
526 dc
.SetBrush(m_brush
);
527 dc
.DrawPolygon(n
, intPoints
, m_xpos
, m_ypos
);
532 void wxPolygonShape::OnDrawOutline(wxDC
& dc
, float x
, float y
, float w
, float h
)
534 dc
.SetBrush(wxTRANSPARENT_BRUSH
);
535 // Multiply all points by proportion of new size to old size
536 float x_proportion
= (float)(fabs(w
/m_originalWidth
));
537 float y_proportion
= (float)(fabs(h
/m_originalHeight
));
539 int n
= m_originalPoints
->Number();
540 wxPoint
*intPoints
= new wxPoint
[n
];
542 for (i
= 0; i
< n
; i
++)
544 wxRealPoint
* point
= (wxRealPoint
*) m_originalPoints
->Nth(i
)->Data();
545 intPoints
[i
].x
= (int) (x_proportion
* point
->x
);
546 intPoints
[i
].y
= (int) (y_proportion
* point
->y
);
548 dc
.DrawPolygon(n
, intPoints
, x
, y
);
552 // Make as many control points as there are vertices.
553 void wxPolygonShape::MakeControlPoints()
555 wxNode
*node
= m_points
->First();
558 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
559 wxPolygonControlPoint
*control
= new wxPolygonControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
,
560 point
, point
->x
, point
->y
);
561 m_canvas
->AddShape(control
);
562 m_controlPoints
.Append(control
);
567 float maxX, maxY, minX, minY;
569 GetBoundingBoxMax(&maxX, &maxY);
570 GetBoundingBoxMin(&minX, &minY);
572 float widthMin = (float)(minX + CONTROL_POINT_SIZE + 2);
573 float heightMin = (float)(minY + CONTROL_POINT_SIZE + 2);
575 // Offsets from main object
576 float top = (float)(- (heightMin / 2.0));
577 float bottom = (float)(heightMin / 2.0 + (maxY - minY));
578 float left = (float)(- (widthMin / 2.0));
579 float right = (float)(widthMin / 2.0 + (maxX - minX));
581 wxControlPoint *control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, top,
582 CONTROL_POINT_DIAGONAL);
583 m_canvas->AddShape(control);
584 m_controlPoints.Append(control);
586 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, 0, top,
587 CONTROL_POINT_VERTICAL);
588 m_canvas->AddShape(control);
589 m_controlPoints.Append(control);
591 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, top,
592 CONTROL_POINT_DIAGONAL);
593 m_canvas->AddShape(control);
594 m_controlPoints.Append(control);
596 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, 0,
597 CONTROL_POINT_HORIZONTAL);
598 m_canvas->AddShape(control);
599 m_controlPoints.Append(control);
601 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, bottom,
602 CONTROL_POINT_DIAGONAL);
603 m_canvas->AddShape(control);
604 m_controlPoints.Append(control);
606 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, 0, bottom,
607 CONTROL_POINT_VERTICAL);
608 m_canvas->AddShape(control);
609 m_controlPoints.Append(control);
611 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, bottom,
612 CONTROL_POINT_DIAGONAL);
613 m_canvas->AddShape(control);
614 m_controlPoints.Append(control);
616 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, 0,
617 CONTROL_POINT_HORIZONTAL);
618 m_canvas->AddShape(control);
619 m_controlPoints.Append(control);
623 void wxPolygonShape::ResetControlPoints()
625 wxNode
*node
= m_points
->First();
626 wxNode
*controlPointNode
= m_controlPoints
.First();
627 while (node
&& controlPointNode
)
629 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
630 wxPolygonControlPoint
*controlPoint
= (wxPolygonControlPoint
*)controlPointNode
->Data();
632 controlPoint
->m_xoffset
= point
->x
;
633 controlPoint
->m_yoffset
= point
->y
;
634 controlPoint
->m_polygonVertex
= point
;
637 controlPointNode
= controlPointNode
->Next();
641 if (m_controlPoints.Number() < 1)
644 float maxX, maxY, minX, minY;
646 GetBoundingBoxMax(&maxX, &maxY);
647 GetBoundingBoxMin(&minX, &minY);
649 float widthMin = (float)(minX + CONTROL_POINT_SIZE + 2);
650 float heightMin = (float)(minY + CONTROL_POINT_SIZE + 2);
652 // Offsets from main object
653 float top = (float)(- (heightMin / 2.0));
654 float bottom = (float)(heightMin / 2.0 + (maxY - minY));
655 float left = (float)(- (widthMin / 2.0));
656 float right = (float)(widthMin / 2.0 + (maxX - minX));
658 wxNode *node = m_controlPoints.First();
659 wxControlPoint *control = (wxControlPoint *)node->Data();
660 control->xoffset = left; control->yoffset = top;
662 node = node->Next(); control = (wxControlPoint *)node->Data();
663 control->xoffset = 0; control->yoffset = top;
665 node = node->Next(); control = (wxControlPoint *)node->Data();
666 control->xoffset = right; control->yoffset = top;
668 node = node->Next(); control = (wxControlPoint *)node->Data();
669 control->xoffset = right; control->yoffset = 0;
671 node = node->Next(); control = (wxControlPoint *)node->Data();
672 control->xoffset = right; control->yoffset = bottom;
674 node = node->Next(); control = (wxControlPoint *)node->Data();
675 control->xoffset = 0; control->yoffset = bottom;
677 node = node->Next(); control = (wxControlPoint *)node->Data();
678 control->xoffset = left; control->yoffset = bottom;
680 node = node->Next(); control = (wxControlPoint *)node->Data();
681 control->xoffset = left; control->yoffset = 0;
687 void wxPolygonShape::WritePrologAttributes(wxExpr
*clause
)
689 wxShape::WritePrologAttributes(clause
);
691 clause
->AddAttributeValue("x", m_xpos
);
692 clause
->AddAttributeValue("y", m_ypos
);
694 // Make a list of lists for the coordinates
695 wxExpr
*list
= new wxExpr(PrologList
);
696 wxNode
*node
= m_points
->First();
699 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
700 wxExpr
*point_list
= new wxExpr(PrologList
);
701 wxExpr
*x_expr
= new wxExpr((float)point
->x
);
702 wxExpr
*y_expr
= new wxExpr((float)point
->y
);
704 point_list
->Append(x_expr
);
705 point_list
->Append(y_expr
);
706 list
->Append(point_list
);
710 clause
->AddAttributeValue("points", list
);
712 // Save the original (unscaled) points
713 list
= new wxExpr(PrologList
);
714 node
= m_originalPoints
->First();
717 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
718 wxExpr
*point_list
= new wxExpr(PrologList
);
719 wxExpr
*x_expr
= new wxExpr((float) point
->x
);
720 wxExpr
*y_expr
= new wxExpr((float) point
->y
);
721 point_list
->Append(x_expr
);
722 point_list
->Append(y_expr
);
723 list
->Append(point_list
);
727 clause
->AddAttributeValue("m_originalPoints", list
);
730 void wxPolygonShape::ReadPrologAttributes(wxExpr
*clause
)
732 wxShape::ReadPrologAttributes(clause
);
734 // Read a list of lists
735 m_points
= new wxList
;
736 m_originalPoints
= new wxList
;
738 wxExpr
*points_list
= NULL
;
739 clause
->AssignAttributeValue("points", &points_list
);
741 // If no points_list, don't crash!! Assume a diamond instead.
742 float the_height
= 100.0;
743 float the_width
= 100.0;
746 wxRealPoint
*point
= new wxRealPoint(0.0, (-the_height
/2));
747 m_points
->Append((wxObject
*) point
);
749 point
= new wxRealPoint((the_width
/2), 0.0);
750 m_points
->Append((wxObject
*) point
);
752 point
= new wxRealPoint(0.0, (the_height
/2));
753 m_points
->Append((wxObject
*) point
);
755 point
= new wxRealPoint((-the_width
/2), 0.0);
756 m_points
->Append((wxObject
*) point
);
758 point
= new wxRealPoint(0.0, (-the_height
/2));
759 m_points
->Append((wxObject
*) point
);
763 wxExpr
*node
= points_list
->value
.first
;
767 wxExpr
*xexpr
= node
->value
.first
;
768 long x
= xexpr
->IntegerValue();
770 wxExpr
*yexpr
= xexpr
->next
;
771 long y
= yexpr
->IntegerValue();
773 wxRealPoint
*point
= new wxRealPoint((float)x
, (float)y
);
774 m_points
->Append((wxObject
*) point
);
781 clause
->AssignAttributeValue("m_originalPoints", &points_list
);
783 // If no points_list, don't crash!! Assume a diamond instead.
786 wxRealPoint
*point
= new wxRealPoint(0.0, (-the_height
/2));
787 m_originalPoints
->Append((wxObject
*) point
);
789 point
= new wxRealPoint((the_width
/2), 0.0);
790 m_originalPoints
->Append((wxObject
*) point
);
792 point
= new wxRealPoint(0.0, (the_height
/2));
793 m_originalPoints
->Append((wxObject
*) point
);
795 point
= new wxRealPoint((-the_width
/2), 0.0);
796 m_originalPoints
->Append((wxObject
*) point
);
798 point
= new wxRealPoint(0.0, (-the_height
/2));
799 m_originalPoints
->Append((wxObject
*) point
);
801 m_originalWidth
= the_width
;
802 m_originalHeight
= the_height
;
806 wxExpr
*node
= points_list
->value
.first
;
813 wxExpr
*xexpr
= node
->value
.first
;
814 long x
= xexpr
->IntegerValue();
816 wxExpr
*yexpr
= xexpr
->next
;
817 long y
= yexpr
->IntegerValue();
819 wxRealPoint
*point
= new wxRealPoint((float)x
, (float)y
);
820 m_originalPoints
->Append((wxObject
*) point
);
833 m_originalWidth
= max_x
- min_x
;
834 m_originalHeight
= max_y
- min_y
;
837 CalculateBoundingBox();
841 void wxPolygonShape::Copy(wxShape
& copy
)
845 wxASSERT( copy
.IsKindOf(CLASSINFO(wxPolygonShape
)) );
847 wxPolygonShape
& polyCopy
= (wxPolygonShape
&) copy
;
849 polyCopy
.ClearPoints();
851 polyCopy
.m_points
= new wxList
;
852 polyCopy
.m_originalPoints
= new wxList
;
854 wxNode
*node
= m_points
->First();
857 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
858 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
859 polyCopy
.m_points
->Append((wxObject
*) new_point
);
862 node
= m_originalPoints
->First();
865 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
866 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
867 polyCopy
.m_originalPoints
->Append((wxObject
*) new_point
);
870 polyCopy
.m_boundWidth
= m_boundWidth
;
871 polyCopy
.m_boundHeight
= m_boundHeight
;
872 polyCopy
.m_originalWidth
= m_originalWidth
;
873 polyCopy
.m_originalHeight
= m_originalHeight
;
876 int wxPolygonShape::GetNumberOfAttachments()
878 int maxN
= (m_points
? (m_points
->Number() - 1) : 0);
879 wxNode
*node
= m_attachmentPoints
.First();
882 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
883 if (point
->m_id
> maxN
)
890 bool wxPolygonShape::GetAttachmentPosition(int attachment
, float *x
, float *y
,
891 int nth
, int no_arcs
, wxLineShape
*line
)
893 if (m_attachmentMode
&& m_points
&& attachment
< m_points
->Number())
895 wxRealPoint
*point
= (wxRealPoint
*)m_points
->Nth(attachment
)->Data();
896 *x
= point
->x
+ m_xpos
;
897 *y
= point
->y
+ m_ypos
;
901 { return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
); }
904 bool wxPolygonShape::AttachmentIsValid(int attachment
)
909 if ((attachment
>= 0) && (attachment
< m_points
->Number()))
912 wxNode
*node
= m_attachmentPoints
.First();
915 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
916 if (point
->m_id
== attachment
)
925 IMPLEMENT_DYNAMIC_CLASS(wxRectangleShape
, wxShape
)
927 wxRectangleShape::wxRectangleShape(float w
, float h
)
929 m_width
= w
; m_height
= h
; m_cornerRadius
= 0.0;
930 SetDefaultRegionSize();
933 void wxRectangleShape::OnDraw(wxDC
& dc
)
935 float x1
= (float)(m_xpos
- m_width
/2.0);
936 float y1
= (float)(m_ypos
- m_height
/2.0);
938 if (m_shadowMode
!= SHADOW_NONE
)
941 dc
.SetBrush(m_shadowBrush
);
942 dc
.SetPen(transparent_pen
);
944 if (m_cornerRadius
!= 0.0)
945 dc
.DrawRoundedRectangle(x1
+ m_shadowOffsetX
, y1
+ m_shadowOffsetY
,
946 m_width
, m_height
, m_cornerRadius
);
948 dc
.DrawRectangle(x1
+ m_shadowOffsetX
, y1
+ m_shadowOffsetY
, m_width
, m_height
);
953 if (m_pen
->GetWidth() == 0)
954 dc
.SetPen(transparent_pen
);
959 dc
.SetBrush(m_brush
);
961 if (m_cornerRadius
!= 0.0)
962 dc
.DrawRoundedRectangle(x1
, y1
, m_width
, m_height
, m_cornerRadius
);
964 dc
.DrawRectangle(x1
, y1
, m_width
, m_height
);
967 void wxRectangleShape::GetBoundingBoxMin(float *the_width
, float *the_height
)
969 *the_width
= m_width
;
970 *the_height
= m_height
;
973 void wxRectangleShape::SetSize(float x
, float y
, bool recursive
)
975 SetAttachmentSize(x
, y
);
976 m_width
= (float)wxMax(x
, 1.0);
977 m_height
= (float)wxMax(y
, 1.0);
978 SetDefaultRegionSize();
981 void wxRectangleShape::SetCornerRadius(float rad
)
983 m_cornerRadius
= rad
;
986 // Assume (x1, y1) is centre of box (most generally, line end at box)
987 bool wxRectangleShape::GetPerimeterPoint(float x1
, float y1
,
989 float *x3
, float *y3
)
991 float bound_x
, bound_y
;
992 GetBoundingBoxMax(&bound_x
, &bound_y
);
993 find_end_for_box(bound_x
, bound_y
, m_xpos
, m_ypos
, x2
, y2
, x3
, y3
);
999 void wxRectangleShape::WritePrologAttributes(wxExpr
*clause
)
1001 wxShape::WritePrologAttributes(clause
);
1002 clause
->AddAttributeValue("x", m_xpos
);
1003 clause
->AddAttributeValue("y", m_ypos
);
1005 clause
->AddAttributeValue("width", m_width
);
1006 clause
->AddAttributeValue("height", m_height
);
1007 if (m_cornerRadius
!= 0.0)
1008 clause
->AddAttributeValue("corner", m_cornerRadius
);
1011 void wxRectangleShape::ReadPrologAttributes(wxExpr
*clause
)
1013 wxShape::ReadPrologAttributes(clause
);
1014 clause
->AssignAttributeValue("width", &m_width
);
1015 clause
->AssignAttributeValue("height", &m_height
);
1016 clause
->AssignAttributeValue("corner", &m_cornerRadius
);
1018 // In case we're reading an old file, set the region's size
1019 if (m_regions
.Number() == 1)
1021 wxShapeRegion
*region
= (wxShapeRegion
*)m_regions
.First()->Data();
1022 region
->SetSize(m_width
, m_height
);
1027 void wxRectangleShape::Copy(wxShape
& copy
)
1029 wxShape::Copy(copy
);
1031 wxASSERT( copy
.IsKindOf(CLASSINFO(wxRectangleShape
)) );
1033 wxRectangleShape
& rectCopy
= (wxRectangleShape
&) copy
;
1034 rectCopy
.m_width
= m_width
;
1035 rectCopy
.m_height
= m_height
;
1036 rectCopy
.m_cornerRadius
= m_cornerRadius
;
1039 int wxRectangleShape::GetNumberOfAttachments()
1041 return wxShape::GetNumberOfAttachments();
1044 // There are 4 attachment points on a rectangle - 0 = top, 1 = right, 2 = bottom,
1046 bool wxRectangleShape::GetAttachmentPosition(int attachment
, float *x
, float *y
,
1047 int nth
, int no_arcs
, wxLineShape
*line
)
1049 if (m_attachmentMode
)
1051 float top
= (float)(m_ypos
+ m_height
/2.0);
1052 float bottom
= (float)(m_ypos
- m_height
/2.0);
1053 float left
= (float)(m_xpos
- m_width
/2.0);
1054 float right
= (float)(m_xpos
+ m_width
/2.0);
1056 bool isEnd
= (line
&& line
->IsEnd(this));
1062 if (m_spaceAttachments
)
1064 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
1066 // Align line according to the next handle along
1067 wxRealPoint
*point
= line
->GetNextControlPoint(this);
1068 if (point
->x
< left
)
1070 else if (point
->x
> right
)
1076 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
1086 if (m_spaceAttachments
)
1088 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
1090 // Align line according to the next handle along
1091 wxRealPoint
*point
= line
->GetNextControlPoint(this);
1092 if (point
->y
< bottom
)
1094 else if (point
->y
> top
)
1100 *y
= bottom
+ (nth
+ 1)*m_height
/(no_arcs
+ 1);
1107 if (m_spaceAttachments
)
1109 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
1111 // Align line according to the next handle along
1112 wxRealPoint
*point
= line
->GetNextControlPoint(this);
1113 if (point
->x
< left
)
1115 else if (point
->x
> right
)
1121 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
1130 if (m_spaceAttachments
)
1132 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
1134 // Align line according to the next handle along
1135 wxRealPoint
*point
= line
->GetNextControlPoint(this);
1136 if (point
->y
< bottom
)
1138 else if (point
->y
> top
)
1144 *y
= bottom
+ (nth
+ 1)*m_height
/(no_arcs
+ 1);
1151 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
1158 { *x
= m_xpos
; *y
= m_ypos
; return TRUE
; }
1161 // Text object (no box)
1163 IMPLEMENT_DYNAMIC_CLASS(wxTextShape
, wxRectangleShape
)
1165 wxTextShape::wxTextShape(float width
, float height
):
1166 wxRectangleShape(width
, height
)
1170 void wxTextShape::OnDraw(wxDC
& dc
)
1174 void wxTextShape::Copy(wxShape
& copy
)
1176 wxRectangleShape::Copy(copy
);
1180 void wxTextShape::WritePrologAttributes(wxExpr
*clause
)
1182 wxRectangleShape::WritePrologAttributes(clause
);
1188 IMPLEMENT_DYNAMIC_CLASS(wxEllipseShape
, wxShape
)
1190 wxEllipseShape::wxEllipseShape(float w
, float h
)
1192 m_width
= w
; m_height
= h
;
1193 SetDefaultRegionSize();
1196 void wxEllipseShape::GetBoundingBoxMin(float *w
, float *h
)
1198 *w
= m_width
; *h
= m_height
;
1201 bool wxEllipseShape::GetPerimeterPoint(float x1
, float y1
,
1203 float *x3
, float *y3
)
1205 float bound_x
, bound_y
;
1206 GetBoundingBoxMax(&bound_x
, &bound_y
);
1208 // find_end_for_box(bound_x, bound_y, m_xpos, m_ypos, x2, y2, x3, y3);
1209 draw_arc_to_ellipse(m_xpos
, m_ypos
, bound_x
, bound_y
, x2
, y2
, x1
, y1
, x3
, y3
);
1214 void wxEllipseShape::OnDraw(wxDC
& dc
)
1216 if (m_shadowMode
!= SHADOW_NONE
)
1219 dc
.SetBrush(m_shadowBrush
);
1220 dc
.SetPen(transparent_pen
);
1221 dc
.DrawEllipse((m_xpos
- GetWidth()/2) + m_shadowOffsetX
,
1222 (m_ypos
- GetHeight()/2) + m_shadowOffsetY
,
1223 GetWidth(), GetHeight());
1228 if (m_pen
->GetWidth() == 0)
1229 dc
.SetPen(transparent_pen
);
1234 dc
.SetBrush(m_brush
);
1235 dc
.DrawEllipse((m_xpos
- GetWidth()/2), (m_ypos
- GetHeight()/2), GetWidth(), GetHeight());
1238 void wxEllipseShape::SetSize(float x
, float y
, bool recursive
)
1240 SetAttachmentSize(x
, y
);
1243 SetDefaultRegionSize();
1247 void wxEllipseShape::WritePrologAttributes(wxExpr
*clause
)
1249 wxShape::WritePrologAttributes(clause
);
1250 clause
->AddAttributeValue("x", m_xpos
);
1251 clause
->AddAttributeValue("y", m_ypos
);
1253 clause
->AddAttributeValue("width", m_width
);
1254 clause
->AddAttributeValue("height", m_height
);
1257 void wxEllipseShape::ReadPrologAttributes(wxExpr
*clause
)
1259 wxShape::ReadPrologAttributes(clause
);
1260 clause
->AssignAttributeValue("width", &m_width
);
1261 clause
->AssignAttributeValue("height", &m_height
);
1263 // In case we're reading an old file, set the region's size
1264 if (m_regions
.Number() == 1)
1266 wxShapeRegion
*region
= (wxShapeRegion
*)m_regions
.First()->Data();
1267 region
->SetSize(m_width
, m_height
);
1272 void wxEllipseShape::Copy(wxShape
& copy
)
1274 wxShape::Copy(copy
);
1276 wxASSERT( copy
.IsKindOf(CLASSINFO(wxEllipseShape
)) );
1278 wxEllipseShape
& ellipseCopy
= (wxEllipseShape
&) copy
;
1280 ellipseCopy
.m_width
= m_width
;
1281 ellipseCopy
.m_height
= m_height
;
1284 int wxEllipseShape::GetNumberOfAttachments()
1286 return wxShape::GetNumberOfAttachments();
1289 // There are 4 attachment points on an ellipse - 0 = top, 1 = right, 2 = bottom,
1291 bool wxEllipseShape::GetAttachmentPosition(int attachment
, float *x
, float *y
,
1292 int nth
, int no_arcs
, wxLineShape
*line
)
1294 if (m_attachmentMode
)
1296 float top
= (float)(m_ypos
+ m_height
/2.0);
1297 float bottom
= (float)(m_ypos
- m_height
/2.0);
1298 float left
= (float)(m_xpos
- m_width
/2.0);
1299 float right
= (float)(m_xpos
+ m_width
/2.0);
1304 if (m_spaceAttachments
)
1305 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
1308 // We now have the point on the bounding box: but get the point on the ellipse
1309 // by imagining a vertical line from (*x, m_ypos - m_height- 500) to (*x, m_ypos) intersecting
1311 draw_arc_to_ellipse(m_xpos
, m_ypos
, m_width
, m_height
, *x
, (float)(m_ypos
-m_height
-500), *x
, m_ypos
, x
, y
);
1317 if (m_spaceAttachments
)
1318 *y
= bottom
+ (nth
+ 1)*m_height
/(no_arcs
+ 1);
1320 draw_arc_to_ellipse(m_xpos
, m_ypos
, m_width
, m_height
, (float)(m_xpos
+m_width
+500), *y
, m_xpos
, *y
, x
, y
);
1325 if (m_spaceAttachments
)
1326 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
1329 draw_arc_to_ellipse(m_xpos
, m_ypos
, m_width
, m_height
, *x
, (float)(m_ypos
+m_height
+500), *x
, m_ypos
, x
, y
);
1335 if (m_spaceAttachments
)
1336 *y
= bottom
+ (nth
+ 1)*m_height
/(no_arcs
+ 1);
1338 draw_arc_to_ellipse(m_xpos
, m_ypos
, m_width
, m_height
, (float)(m_xpos
-m_width
-500), *y
, m_xpos
, *y
, x
, y
);
1343 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
1350 { *x
= m_xpos
; *y
= m_ypos
; return TRUE
; }
1355 IMPLEMENT_DYNAMIC_CLASS(wxCircleShape
, wxEllipseShape
)
1357 wxCircleShape::wxCircleShape(float diameter
):wxEllipseShape(diameter
, diameter
)
1361 void wxCircleShape::Copy(wxShape
& copy
)
1363 wxEllipseShape::Copy(copy
);
1366 bool wxCircleShape::GetPerimeterPoint(float x1
, float y1
,
1368 float *x3
, float *y3
)
1370 find_end_for_circle(m_width
/2,
1371 m_xpos
, m_ypos
, // Centre of circle
1372 x2
, y2
, // Other end of line
1380 float wxControlPoint::controlPointDragStartX
= 0.0;
1381 float wxControlPoint::controlPointDragStartY
= 0.0;
1382 float wxControlPoint::controlPointDragStartWidth
= 0.0;
1383 float wxControlPoint::controlPointDragStartHeight
= 0.0;
1384 float wxControlPoint::controlPointDragEndWidth
= 0.0;
1385 float wxControlPoint::controlPointDragEndHeight
= 0.0;
1386 float wxControlPoint::controlPointDragPosX
= 0.0;
1387 float wxControlPoint::controlPointDragPosY
= 0.0;
1389 IMPLEMENT_DYNAMIC_CLASS(wxControlPoint
, wxRectangleShape
)
1391 wxControlPoint::wxControlPoint(wxShapeCanvas
*theCanvas
, wxShape
*object
, float size
, float the_xoffset
, float the_yoffset
, int the_type
):wxRectangleShape(size
, size
)
1393 m_canvas
= theCanvas
;
1395 m_xoffset
= the_xoffset
;
1396 m_yoffset
= the_yoffset
;
1398 SetPen(black_foreground_pen
);
1399 SetBrush(wxBLACK_BRUSH
);
1402 m_eraseObject
= TRUE
;
1405 wxControlPoint::~wxControlPoint()
1409 // Don't even attempt to draw any text - waste of time!
1410 void wxControlPoint::OnDrawContents(wxDC
& dc
)
1414 void wxControlPoint::OnDraw(wxDC
& dc
)
1416 m_xpos
= m_shape
->GetX() + m_xoffset
;
1417 m_ypos
= m_shape
->GetY() + m_yoffset
;
1418 wxRectangleShape::OnDraw(dc
);
1421 void wxControlPoint::OnErase(wxDC
& dc
)
1423 wxRectangleShape::OnErase(dc
);
1426 // Implement resizing of canvas object
1427 void wxControlPoint::OnDragLeft(bool draw
, float x
, float y
, int keys
, int attachment
)
1429 m_shape
->GetEventHandler()->OnSizingDragLeft(this, draw
, x
, y
, keys
, attachment
);
1432 void wxControlPoint::OnBeginDragLeft(float x
, float y
, int keys
, int attachment
)
1434 m_shape
->GetEventHandler()->OnSizingBeginDragLeft(this, x
, y
, keys
, attachment
);
1437 void wxControlPoint::OnEndDragLeft(float x
, float y
, int keys
, int attachment
)
1439 m_shape
->GetEventHandler()->OnSizingEndDragLeft(this, x
, y
, keys
, attachment
);
1442 int wxControlPoint::GetNumberOfAttachments()
1447 bool wxControlPoint::GetAttachmentPosition(int attachment
, float *x
, float *y
,
1448 int nth
, int no_arcs
, wxLineShape
*line
)
1450 *x
= m_xpos
; *y
= m_ypos
;
1454 // Control points ('handles') redirect control to the actual shape, to make it easier
1455 // to override sizing behaviour.
1456 void wxShape::OnSizingDragLeft(wxControlPoint
* pt
, bool draw
, float x
, float y
, int keys
, int attachment
)
1460 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1462 wxClientDC
dc(GetCanvas());
1463 GetCanvas()->PrepareDC(dc
);
1465 dc
.SetLogicalFunction(wxXOR
);
1467 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1468 dc
.SetPen(dottedPen
);
1469 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1471 if (this->GetCentreResize())
1473 // Maintain the same centre point.
1474 float new_width
= (float)(2.0*fabs(x
- this->GetX()));
1475 float new_height
= (float)(2.0*fabs(y
- this->GetY()));
1477 // Constrain sizing according to what control point you're dragging
1478 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1479 new_height
= bound_y
;
1480 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1481 new_width
= bound_x
;
1482 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& (keys
& KEY_SHIFT
))
1483 new_height
= bound_y
*(new_width
/bound_x
);
1485 if (this->GetFixedWidth())
1486 new_width
= bound_x
;
1488 if (this->GetFixedHeight())
1489 new_height
= bound_y
;
1491 pt
->controlPointDragEndWidth
= new_width
;
1492 pt
->controlPointDragEndHeight
= new_height
;
1494 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1495 new_width
, new_height
);
1499 // Don't maintain the same centre point!
1500 float newX1
= wxMin(pt
->controlPointDragStartX
, x
);
1501 float newY1
= wxMin(pt
->controlPointDragStartY
, y
);
1502 float newX2
= wxMax(pt
->controlPointDragStartX
, x
);
1503 float newY2
= wxMax(pt
->controlPointDragStartY
, y
);
1504 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1506 newY1
= pt
->controlPointDragStartY
;
1507 newY2
= newY1
+ pt
->controlPointDragStartHeight
;
1509 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1511 newX1
= pt
->controlPointDragStartX
;
1512 newX2
= newX1
+ pt
->controlPointDragStartWidth
;
1514 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& (keys
& KEY_SHIFT
))
1516 float newH
= (float)((newX2
- newX1
)*(pt
->controlPointDragStartHeight
/pt
->controlPointDragStartWidth
));
1517 if (GetY() > pt
->controlPointDragStartY
)
1518 newY2
= (float)(newY1
+ newH
);
1520 newY1
= (float)(newY2
- newH
);
1522 float newWidth
= (float)(newX2
- newX1
);
1523 float newHeight
= (float)(newY2
- newY1
);
1525 pt
->controlPointDragPosX
= (float)(newX1
+ (newWidth
/2.0));
1526 pt
->controlPointDragPosY
= (float)(newY1
+ (newHeight
/2.0));
1527 if (this->GetFixedWidth())
1530 if (this->GetFixedHeight())
1531 newHeight
= bound_y
;
1533 pt
->controlPointDragEndWidth
= newWidth
;
1534 pt
->controlPointDragEndHeight
= newHeight
;
1535 this->GetEventHandler()->OnDrawOutline(dc
, pt
->controlPointDragPosX
, pt
->controlPointDragPosY
, newWidth
, newHeight
);
1539 void wxShape::OnSizingBeginDragLeft(wxControlPoint
* pt
, float x
, float y
, int keys
, int attachment
)
1541 m_canvas
->CaptureMouse();
1543 wxClientDC
dc(GetCanvas());
1544 GetCanvas()->PrepareDC(dc
);
1546 if (pt
->m_eraseObject
)
1549 dc
.SetLogicalFunction(wxXOR
);
1553 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1555 // Choose the 'opposite corner' of the object as the stationary
1556 // point in case this is non-centring resizing.
1557 if (pt
->GetX() < this->GetX())
1558 pt
->controlPointDragStartX
= (float)(this->GetX() + (bound_x
/2.0));
1560 pt
->controlPointDragStartX
= (float)(this->GetX() - (bound_x
/2.0));
1562 if (pt
->GetY() < this->GetY())
1563 pt
->controlPointDragStartY
= (float)(this->GetY() + (bound_y
/2.0));
1565 pt
->controlPointDragStartY
= (float)(this->GetY() - (bound_y
/2.0));
1567 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1568 pt
->controlPointDragStartY
= (float)(this->GetY() - (bound_y
/2.0));
1569 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1570 pt
->controlPointDragStartX
= (float)(this->GetX() - (bound_x
/2.0));
1572 // We may require the old width and height.
1573 pt
->controlPointDragStartWidth
= bound_x
;
1574 pt
->controlPointDragStartHeight
= bound_y
;
1576 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1577 dc
.SetPen(dottedPen
);
1578 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1580 if (this->GetCentreResize())
1582 float new_width
= (float)(2.0*fabs(x
- this->GetX()));
1583 float new_height
= (float)(2.0*fabs(y
- this->GetY()));
1585 // Constrain sizing according to what control point you're dragging
1586 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1587 new_height
= bound_y
;
1588 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1589 new_width
= bound_x
;
1590 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& (keys
& KEY_SHIFT
))
1591 new_height
= bound_y
*(new_width
/bound_x
);
1593 if (this->GetFixedWidth())
1594 new_width
= bound_x
;
1596 if (this->GetFixedHeight())
1597 new_height
= bound_y
;
1599 pt
->controlPointDragEndWidth
= new_width
;
1600 pt
->controlPointDragEndHeight
= new_height
;
1601 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1602 new_width
, new_height
);
1606 // Don't maintain the same centre point!
1607 float newX1
= wxMin(pt
->controlPointDragStartX
, x
);
1608 float newY1
= wxMin(pt
->controlPointDragStartY
, y
);
1609 float newX2
= wxMax(pt
->controlPointDragStartX
, x
);
1610 float newY2
= wxMax(pt
->controlPointDragStartY
, y
);
1611 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1613 newY1
= pt
->controlPointDragStartY
;
1614 newY2
= newY1
+ pt
->controlPointDragStartHeight
;
1616 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1618 newX1
= pt
->controlPointDragStartX
;
1619 newX2
= newX1
+ pt
->controlPointDragStartWidth
;
1621 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& (keys
& KEY_SHIFT
))
1623 float newH
= (float)((newX2
- newX1
)*(pt
->controlPointDragStartHeight
/pt
->controlPointDragStartWidth
));
1624 if (pt
->GetY() > pt
->controlPointDragStartY
)
1625 newY2
= (float)(newY1
+ newH
);
1627 newY1
= (float)(newY2
- newH
);
1629 float newWidth
= (float)(newX2
- newX1
);
1630 float newHeight
= (float)(newY2
- newY1
);
1632 pt
->controlPointDragPosX
= (float)(newX1
+ (newWidth
/2.0));
1633 pt
->controlPointDragPosY
= (float)(newY1
+ (newHeight
/2.0));
1634 if (this->GetFixedWidth())
1637 if (this->GetFixedHeight())
1638 newHeight
= bound_y
;
1640 pt
->controlPointDragEndWidth
= newWidth
;
1641 pt
->controlPointDragEndHeight
= newHeight
;
1642 this->GetEventHandler()->OnDrawOutline(dc
, pt
->controlPointDragPosX
, pt
->controlPointDragPosY
, newWidth
, newHeight
);
1646 void wxShape::OnSizingEndDragLeft(wxControlPoint
* pt
, float x
, float y
, int keys
, int attachment
)
1648 wxClientDC
dc(GetCanvas());
1649 GetCanvas()->PrepareDC(dc
);
1651 m_canvas
->ReleaseMouse();
1652 dc
.SetLogicalFunction(wxCOPY
);
1654 this->ResetControlPoints();
1656 if (!pt
->m_eraseObject
)
1659 this->SetSize(pt
->controlPointDragEndWidth
, pt
->controlPointDragEndHeight
);
1661 // The next operation could destroy this control point (it does for label objects,
1662 // via formatting the text), so save all values we're going to use, or
1663 // we'll be accessing garbage.
1664 wxShape
*theObject
= this;
1665 wxShapeCanvas
*theCanvas
= m_canvas
;
1666 bool eraseIt
= pt
->m_eraseObject
;
1668 if (theObject
->GetCentreResize())
1669 theObject
->Move(dc
, theObject
->GetX(), theObject
->GetY());
1671 theObject
->Move(dc
, pt
->controlPointDragPosX
, pt
->controlPointDragPosY
);
1674 theObject
->Show(TRUE
);
1676 // Recursively redraw links if we have a composite.
1677 if (theObject
->GetChildren().Number() > 0)
1678 theObject
->DrawLinks(dc
, -1, TRUE
);
1680 float width
, height
;
1681 theObject
->GetBoundingBoxMax(&width
, &height
);
1682 theObject
->GetEventHandler()->OnEndSize(width
, height
);
1684 if (!theCanvas
->GetQuickEditMode() && eraseIt
) theCanvas
->Redraw(dc
);
1689 // Polygon control points
1691 IMPLEMENT_DYNAMIC_CLASS(wxPolygonControlPoint
, wxControlPoint
)
1693 wxPolygonControlPoint::wxPolygonControlPoint(wxShapeCanvas
*theCanvas
, wxShape
*object
, float size
,
1694 wxRealPoint
*vertex
, float the_xoffset
, float the_yoffset
):
1695 wxControlPoint(theCanvas
, object
, size
, the_xoffset
, the_yoffset
, 0)
1697 m_polygonVertex
= vertex
;
1698 m_originalDistance
= 0.0;
1701 wxPolygonControlPoint::~wxPolygonControlPoint()
1705 // Calculate what new size would be, at end of resize
1706 void wxPolygonControlPoint::CalculateNewSize(float x
, float y
)
1710 GetShape()->GetBoundingBoxMin(&bound_x
, &bound_y
);
1712 float dist
= (float)sqrt((x
- m_shape
->GetX())*(x
- m_shape
->GetX()) +
1713 (y
- m_shape
->GetY())*(y
- m_shape
->GetY()));
1715 m_newSize
.x
= (float)(dist
/this->m_originalDistance
)*this->m_originalSize
.x
;
1716 m_newSize
.y
= (float)(dist
/this->m_originalDistance
)*this->m_originalSize
.y
;
1720 // Implement resizing polygon or moving the vertex.
1721 void wxPolygonControlPoint::OnDragLeft(bool draw
, float x
, float y
, int keys
, int attachment
)
1723 m_shape
->GetEventHandler()->OnSizingDragLeft(this, draw
, x
, y
, keys
, attachment
);
1726 void wxPolygonControlPoint::OnBeginDragLeft(float x
, float y
, int keys
, int attachment
)
1728 m_shape
->GetEventHandler()->OnSizingBeginDragLeft(this, x
, y
, keys
, attachment
);
1731 void wxPolygonControlPoint::OnEndDragLeft(float x
, float y
, int keys
, int attachment
)
1733 m_shape
->GetEventHandler()->OnSizingEndDragLeft(this, x
, y
, keys
, attachment
);
1736 // Control points ('handles') redirect control to the actual shape, to make it easier
1737 // to override sizing behaviour.
1738 void wxPolygonShape::OnSizingDragLeft(wxControlPoint
* pt
, bool draw
, float x
, float y
, int keys
, int attachment
)
1740 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
1742 wxClientDC
dc(GetCanvas());
1743 GetCanvas()->PrepareDC(dc
);
1745 dc
.SetLogicalFunction(wxXOR
);
1747 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1748 dc
.SetPen(dottedPen
);
1749 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1751 if (0) // keys & KEY_CTRL)
1753 // TODO: mend this code. Currently we rely on altering the
1754 // actual points, but we should assume we're not, as per
1755 // the normal sizing case.
1756 m_canvas
->Snap(&x
, &y
);
1759 ppt
->m_polygonVertex
->x
= x
- this->GetX();
1760 ppt
->m_polygonVertex
->y
= y
- this->GetY();
1763 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1764 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1768 ppt
->CalculateNewSize(x
, y
);
1771 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1772 ppt
->GetNewSize().x
, ppt
->GetNewSize().y
);
1775 void wxPolygonShape::OnSizingBeginDragLeft(wxControlPoint
* pt
, float x
, float y
, int keys
, int attachment
)
1777 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
1779 wxClientDC
dc(GetCanvas());
1780 GetCanvas()->PrepareDC(dc
);
1784 dc
.SetLogicalFunction(wxXOR
);
1788 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1790 float dist
= (float)sqrt((x
- this->GetX())*(x
- this->GetX()) +
1791 (y
- this->GetY())*(y
- this->GetY()));
1792 ppt
->m_originalDistance
= dist
;
1793 ppt
->m_originalSize
.x
= bound_x
;
1794 ppt
->m_originalSize
.y
= bound_y
;
1796 if (ppt
->m_originalDistance
== 0.0) ppt
->m_originalDistance
= (float) 0.0001;
1798 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1799 dc
.SetPen(dottedPen
);
1800 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1802 if (0) // keys & KEY_CTRL)
1804 // TODO: mend this code. Currently we rely on altering the
1805 // actual points, but we should assume we're not, as per
1806 // the normal sizing case.
1807 m_canvas
->Snap(&x
, &y
);
1810 ppt
->m_polygonVertex
->x
= x
- this->GetX();
1811 ppt
->m_polygonVertex
->y
= y
- this->GetY();
1814 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1815 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1819 ppt
->CalculateNewSize(x
, y
);
1822 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1823 ppt
->GetNewSize().x
, ppt
->GetNewSize().y
);
1825 m_canvas
->CaptureMouse();
1828 void wxPolygonShape::OnSizingEndDragLeft(wxControlPoint
* pt
, float x
, float y
, int keys
, int attachment
)
1830 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
1832 wxClientDC
dc(GetCanvas());
1833 GetCanvas()->PrepareDC(dc
);
1835 m_canvas
->ReleaseMouse();
1836 dc
.SetLogicalFunction(wxCOPY
);
1838 // If we're changing shape, must reset the original points
1839 if (keys
& KEY_CTRL
)
1841 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1842 ((wxPolygonShape
*)this)->UpdateOriginalPoints();
1846 SetSize(ppt
->GetNewSize().x
, ppt
->GetNewSize().y
);
1849 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1850 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1853 this->ResetControlPoints();
1854 this->Move(dc
, this->GetX(), this->GetY());
1855 if (!m_canvas
->GetQuickEditMode()) m_canvas
->Redraw(dc
);
1862 IMPLEMENT_DYNAMIC_CLASS(wxShapeRegion
, wxObject
)
1864 wxShapeRegion::wxShapeRegion()
1867 m_font
= g_oglNormalFont
;
1875 m_regionProportionX
= -1.0;
1876 m_regionProportionY
= -1.0;
1877 m_formatMode
= FORMAT_CENTRE_HORIZ
| FORMAT_CENTRE_VERT
;
1879 m_textColour
= "BLACK";
1880 m_penColour
= "BLACK";
1881 m_penStyle
= wxSOLID
;
1882 m_actualColourObject
= NULL
;
1883 m_actualPenObject
= NULL
;
1886 wxShapeRegion::wxShapeRegion(wxShapeRegion
& region
)
1888 m_regionText
= region
.m_regionText
;
1889 m_regionName
= region
.m_regionName
;
1890 m_textColour
= region
.m_textColour
;
1892 m_font
= region
.m_font
;
1893 m_minHeight
= region
.m_minHeight
;
1894 m_minWidth
= region
.m_minWidth
;
1895 m_width
= region
.m_width
;
1896 m_height
= region
.m_height
;
1900 m_regionProportionX
= region
.m_regionProportionX
;
1901 m_regionProportionY
= region
.m_regionProportionY
;
1902 m_formatMode
= region
.m_formatMode
;
1903 m_actualColourObject
= NULL
;
1904 m_actualPenObject
= NULL
;
1905 m_penStyle
= region
.m_penStyle
;
1906 m_penColour
= region
.m_penColour
;
1909 wxNode
*node
= region
.m_formattedText
.First();
1912 wxShapeTextLine
*line
= (wxShapeTextLine
*)node
->Data();
1913 wxShapeTextLine
*new_line
=
1914 new wxShapeTextLine(line
->GetX(), line
->GetY(), line
->GetText());
1915 m_formattedText
.Append(new_line
);
1916 node
= node
->Next();
1920 wxShapeRegion::~wxShapeRegion()
1925 void wxShapeRegion::ClearText()
1927 wxNode
*node
= m_formattedText
.First();
1930 wxShapeTextLine
*line
= (wxShapeTextLine
*)node
->Data();
1931 wxNode
*next
= node
->Next();
1938 void wxShapeRegion::SetFont(wxFont
*f
)
1943 void wxShapeRegion::SetMinSize(float w
, float h
)
1949 void wxShapeRegion::SetSize(float w
, float h
)
1955 void wxShapeRegion::SetPosition(float xp
, float yp
)
1961 void wxShapeRegion::SetProportions(float xp
, float yp
)
1963 m_regionProportionX
= xp
;
1964 m_regionProportionY
= yp
;
1967 void wxShapeRegion::SetFormatMode(int mode
)
1969 m_formatMode
= mode
;
1972 void wxShapeRegion::SetColour(const wxString
& col
)
1975 m_actualColourObject
= NULL
;
1978 wxColour
*wxShapeRegion::GetActualColourObject()
1980 if (!m_actualColourObject
)
1981 m_actualColourObject
= wxTheColourDatabase
->FindColour(GetColour());
1982 if (!m_actualColourObject
)
1983 m_actualColourObject
= wxBLACK
;
1984 return m_actualColourObject
;
1987 void wxShapeRegion::SetPenColour(const wxString
& col
)
1990 m_actualPenObject
= NULL
;
1993 // Returns NULL if the pen is invisible
1994 // (different to pen being transparent; indicates that
1995 // region boundary should not be drawn.)
1996 wxPen
*wxShapeRegion::GetActualPen()
1998 if (m_actualPenObject
)
1999 return m_actualPenObject
;
2001 if (!m_penColour
) return NULL
;
2002 if (m_penColour
== "Invisible")
2004 m_actualPenObject
= wxThePenList
->FindOrCreatePen(m_penColour
, 1, m_penStyle
);
2005 return m_actualPenObject
;