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
);
536 int n
= m_points
->Number();
537 wxPoint
*intPoints
= new wxPoint
[n
];
539 for (i
= 0; i
< n
; i
++)
541 wxRealPoint
* point
= (wxRealPoint
*) m_points
->Nth(i
)->Data();
542 intPoints
[i
].x
= (int) point
->x
;
543 intPoints
[i
].y
= (int) point
->y
;
545 dc
.DrawPolygon(n
, intPoints
, x
, y
);
549 // Make as many control points as there are vertices.
550 void wxPolygonShape::MakeControlPoints()
552 wxNode
*node
= m_points
->First();
555 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
556 wxPolygonControlPoint
*control
= new wxPolygonControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
,
557 point
, point
->x
, point
->y
);
558 m_canvas
->AddShape(control
);
559 m_controlPoints
.Append(control
);
564 float maxX, maxY, minX, minY;
566 GetBoundingBoxMax(&maxX, &maxY);
567 GetBoundingBoxMin(&minX, &minY);
569 float widthMin = (float)(minX + CONTROL_POINT_SIZE + 2);
570 float heightMin = (float)(minY + CONTROL_POINT_SIZE + 2);
572 // Offsets from main object
573 float top = (float)(- (heightMin / 2.0));
574 float bottom = (float)(heightMin / 2.0 + (maxY - minY));
575 float left = (float)(- (widthMin / 2.0));
576 float right = (float)(widthMin / 2.0 + (maxX - minX));
578 wxControlPoint *control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, top,
579 CONTROL_POINT_DIAGONAL);
580 m_canvas->AddShape(control);
581 m_controlPoints.Append(control);
583 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, 0, top,
584 CONTROL_POINT_VERTICAL);
585 m_canvas->AddShape(control);
586 m_controlPoints.Append(control);
588 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, top,
589 CONTROL_POINT_DIAGONAL);
590 m_canvas->AddShape(control);
591 m_controlPoints.Append(control);
593 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, 0,
594 CONTROL_POINT_HORIZONTAL);
595 m_canvas->AddShape(control);
596 m_controlPoints.Append(control);
598 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, bottom,
599 CONTROL_POINT_DIAGONAL);
600 m_canvas->AddShape(control);
601 m_controlPoints.Append(control);
603 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, 0, bottom,
604 CONTROL_POINT_VERTICAL);
605 m_canvas->AddShape(control);
606 m_controlPoints.Append(control);
608 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, bottom,
609 CONTROL_POINT_DIAGONAL);
610 m_canvas->AddShape(control);
611 m_controlPoints.Append(control);
613 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, 0,
614 CONTROL_POINT_HORIZONTAL);
615 m_canvas->AddShape(control);
616 m_controlPoints.Append(control);
620 void wxPolygonShape::ResetControlPoints()
622 wxNode
*node
= m_points
->First();
623 wxNode
*controlPointNode
= m_controlPoints
.First();
624 while (node
&& controlPointNode
)
626 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
627 wxPolygonControlPoint
*controlPoint
= (wxPolygonControlPoint
*)controlPointNode
->Data();
629 controlPoint
->m_xoffset
= point
->x
;
630 controlPoint
->m_yoffset
= point
->y
;
631 controlPoint
->m_polygonVertex
= point
;
634 controlPointNode
= controlPointNode
->Next();
638 if (m_controlPoints.Number() < 1)
641 float maxX, maxY, minX, minY;
643 GetBoundingBoxMax(&maxX, &maxY);
644 GetBoundingBoxMin(&minX, &minY);
646 float widthMin = (float)(minX + CONTROL_POINT_SIZE + 2);
647 float heightMin = (float)(minY + CONTROL_POINT_SIZE + 2);
649 // Offsets from main object
650 float top = (float)(- (heightMin / 2.0));
651 float bottom = (float)(heightMin / 2.0 + (maxY - minY));
652 float left = (float)(- (widthMin / 2.0));
653 float right = (float)(widthMin / 2.0 + (maxX - minX));
655 wxNode *node = m_controlPoints.First();
656 wxControlPoint *control = (wxControlPoint *)node->Data();
657 control->xoffset = left; control->yoffset = top;
659 node = node->Next(); control = (wxControlPoint *)node->Data();
660 control->xoffset = 0; control->yoffset = top;
662 node = node->Next(); control = (wxControlPoint *)node->Data();
663 control->xoffset = right; control->yoffset = top;
665 node = node->Next(); control = (wxControlPoint *)node->Data();
666 control->xoffset = right; control->yoffset = 0;
668 node = node->Next(); control = (wxControlPoint *)node->Data();
669 control->xoffset = right; control->yoffset = bottom;
671 node = node->Next(); control = (wxControlPoint *)node->Data();
672 control->xoffset = 0; control->yoffset = bottom;
674 node = node->Next(); control = (wxControlPoint *)node->Data();
675 control->xoffset = left; control->yoffset = bottom;
677 node = node->Next(); control = (wxControlPoint *)node->Data();
678 control->xoffset = left; control->yoffset = 0;
684 void wxPolygonShape::WritePrologAttributes(wxExpr
*clause
)
686 wxShape::WritePrologAttributes(clause
);
688 clause
->AddAttributeValue("x", m_xpos
);
689 clause
->AddAttributeValue("y", m_ypos
);
691 // Make a list of lists for the coordinates
692 wxExpr
*list
= new wxExpr(PrologList
);
693 wxNode
*node
= m_points
->First();
696 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
697 wxExpr
*point_list
= new wxExpr(PrologList
);
698 wxExpr
*x_expr
= new wxExpr((float)point
->x
);
699 wxExpr
*y_expr
= new wxExpr((float)point
->y
);
701 point_list
->Append(x_expr
);
702 point_list
->Append(y_expr
);
703 list
->Append(point_list
);
707 clause
->AddAttributeValue("points", list
);
709 // Save the original (unscaled) points
710 list
= new wxExpr(PrologList
);
711 node
= m_originalPoints
->First();
714 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
715 wxExpr
*point_list
= new wxExpr(PrologList
);
716 wxExpr
*x_expr
= new wxExpr((float) point
->x
);
717 wxExpr
*y_expr
= new wxExpr((float) point
->y
);
718 point_list
->Append(x_expr
);
719 point_list
->Append(y_expr
);
720 list
->Append(point_list
);
724 clause
->AddAttributeValue("m_originalPoints", list
);
727 void wxPolygonShape::ReadPrologAttributes(wxExpr
*clause
)
729 wxShape::ReadPrologAttributes(clause
);
731 // Read a list of lists
732 m_points
= new wxList
;
733 m_originalPoints
= new wxList
;
735 wxExpr
*points_list
= NULL
;
736 clause
->AssignAttributeValue("points", &points_list
);
738 // If no points_list, don't crash!! Assume a diamond instead.
739 float the_height
= 100.0;
740 float the_width
= 100.0;
743 wxRealPoint
*point
= new wxRealPoint(0.0, (-the_height
/2));
744 m_points
->Append((wxObject
*) point
);
746 point
= new wxRealPoint((the_width
/2), 0.0);
747 m_points
->Append((wxObject
*) point
);
749 point
= new wxRealPoint(0.0, (the_height
/2));
750 m_points
->Append((wxObject
*) point
);
752 point
= new wxRealPoint((-the_width
/2), 0.0);
753 m_points
->Append((wxObject
*) point
);
755 point
= new wxRealPoint(0.0, (-the_height
/2));
756 m_points
->Append((wxObject
*) point
);
760 wxExpr
*node
= points_list
->value
.first
;
764 wxExpr
*xexpr
= node
->value
.first
;
765 long x
= xexpr
->IntegerValue();
767 wxExpr
*yexpr
= xexpr
->next
;
768 long y
= yexpr
->IntegerValue();
770 wxRealPoint
*point
= new wxRealPoint((float)x
, (float)y
);
771 m_points
->Append((wxObject
*) point
);
778 clause
->AssignAttributeValue("m_originalPoints", &points_list
);
780 // If no points_list, don't crash!! Assume a diamond instead.
783 wxRealPoint
*point
= new wxRealPoint(0.0, (-the_height
/2));
784 m_originalPoints
->Append((wxObject
*) point
);
786 point
= new wxRealPoint((the_width
/2), 0.0);
787 m_originalPoints
->Append((wxObject
*) point
);
789 point
= new wxRealPoint(0.0, (the_height
/2));
790 m_originalPoints
->Append((wxObject
*) point
);
792 point
= new wxRealPoint((-the_width
/2), 0.0);
793 m_originalPoints
->Append((wxObject
*) point
);
795 point
= new wxRealPoint(0.0, (-the_height
/2));
796 m_originalPoints
->Append((wxObject
*) point
);
798 m_originalWidth
= the_width
;
799 m_originalHeight
= the_height
;
803 wxExpr
*node
= points_list
->value
.first
;
810 wxExpr
*xexpr
= node
->value
.first
;
811 long x
= xexpr
->IntegerValue();
813 wxExpr
*yexpr
= xexpr
->next
;
814 long y
= yexpr
->IntegerValue();
816 wxRealPoint
*point
= new wxRealPoint((float)x
, (float)y
);
817 m_originalPoints
->Append((wxObject
*) point
);
830 m_originalWidth
= max_x
- min_x
;
831 m_originalHeight
= max_y
- min_y
;
834 CalculateBoundingBox();
838 void wxPolygonShape::Copy(wxShape
& copy
)
842 wxASSERT( copy
.IsKindOf(CLASSINFO(wxPolygonShape
)) );
844 wxPolygonShape
& polyCopy
= (wxPolygonShape
&) copy
;
846 polyCopy
.ClearPoints();
848 polyCopy
.m_points
= new wxList
;
849 polyCopy
.m_originalPoints
= new wxList
;
851 wxNode
*node
= m_points
->First();
854 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
855 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
856 polyCopy
.m_points
->Append((wxObject
*) new_point
);
859 node
= m_originalPoints
->First();
862 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
863 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
864 polyCopy
.m_originalPoints
->Append((wxObject
*) new_point
);
867 polyCopy
.m_boundWidth
= m_boundWidth
;
868 polyCopy
.m_boundHeight
= m_boundHeight
;
869 polyCopy
.m_originalWidth
= m_originalWidth
;
870 polyCopy
.m_originalHeight
= m_originalHeight
;
873 int wxPolygonShape::GetNumberOfAttachments()
875 int maxN
= (m_points
? (m_points
->Number() - 1) : 0);
876 wxNode
*node
= m_attachmentPoints
.First();
879 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
880 if (point
->m_id
> maxN
)
887 bool wxPolygonShape::GetAttachmentPosition(int attachment
, float *x
, float *y
,
888 int nth
, int no_arcs
, wxLineShape
*line
)
890 if (m_attachmentMode
&& m_points
&& attachment
< m_points
->Number())
892 wxRealPoint
*point
= (wxRealPoint
*)m_points
->Nth(attachment
)->Data();
893 *x
= point
->x
+ m_xpos
;
894 *y
= point
->y
+ m_ypos
;
898 { return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
); }
901 bool wxPolygonShape::AttachmentIsValid(int attachment
)
906 if ((attachment
>= 0) && (attachment
< m_points
->Number()))
909 wxNode
*node
= m_attachmentPoints
.First();
912 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
913 if (point
->m_id
== attachment
)
922 IMPLEMENT_DYNAMIC_CLASS(wxRectangleShape
, wxShape
)
924 wxRectangleShape::wxRectangleShape(float w
, float h
)
926 m_width
= w
; m_height
= h
; m_cornerRadius
= 0.0;
927 SetDefaultRegionSize();
930 void wxRectangleShape::OnDraw(wxDC
& dc
)
932 float x1
= (float)(m_xpos
- m_width
/2.0);
933 float y1
= (float)(m_ypos
- m_height
/2.0);
935 if (m_shadowMode
!= SHADOW_NONE
)
938 dc
.SetBrush(m_shadowBrush
);
939 dc
.SetPen(transparent_pen
);
941 if (m_cornerRadius
!= 0.0)
942 dc
.DrawRoundedRectangle(x1
+ m_shadowOffsetX
, y1
+ m_shadowOffsetY
,
943 m_width
, m_height
, m_cornerRadius
);
945 dc
.DrawRectangle(x1
+ m_shadowOffsetX
, y1
+ m_shadowOffsetY
, m_width
, m_height
);
950 if (m_pen
->GetWidth() == 0)
951 dc
.SetPen(transparent_pen
);
956 dc
.SetBrush(m_brush
);
958 if (m_cornerRadius
!= 0.0)
959 dc
.DrawRoundedRectangle(x1
, y1
, m_width
, m_height
, m_cornerRadius
);
961 dc
.DrawRectangle(x1
, y1
, m_width
, m_height
);
964 void wxRectangleShape::GetBoundingBoxMin(float *the_width
, float *the_height
)
966 *the_width
= m_width
;
967 *the_height
= m_height
;
970 void wxRectangleShape::SetSize(float x
, float y
, bool recursive
)
972 SetAttachmentSize(x
, y
);
973 m_width
= (float)wxMax(x
, 1.0);
974 m_height
= (float)wxMax(y
, 1.0);
975 SetDefaultRegionSize();
978 void wxRectangleShape::SetCornerRadius(float rad
)
980 m_cornerRadius
= rad
;
983 // Assume (x1, y1) is centre of box (most generally, line end at box)
984 bool wxRectangleShape::GetPerimeterPoint(float x1
, float y1
,
986 float *x3
, float *y3
)
988 float bound_x
, bound_y
;
989 GetBoundingBoxMax(&bound_x
, &bound_y
);
990 find_end_for_box(bound_x
, bound_y
, m_xpos
, m_ypos
, x2
, y2
, x3
, y3
);
996 void wxRectangleShape::WritePrologAttributes(wxExpr
*clause
)
998 wxShape::WritePrologAttributes(clause
);
999 clause
->AddAttributeValue("x", m_xpos
);
1000 clause
->AddAttributeValue("y", m_ypos
);
1002 clause
->AddAttributeValue("width", m_width
);
1003 clause
->AddAttributeValue("height", m_height
);
1004 if (m_cornerRadius
!= 0.0)
1005 clause
->AddAttributeValue("corner", m_cornerRadius
);
1008 void wxRectangleShape::ReadPrologAttributes(wxExpr
*clause
)
1010 wxShape::ReadPrologAttributes(clause
);
1011 clause
->AssignAttributeValue("width", &m_width
);
1012 clause
->AssignAttributeValue("height", &m_height
);
1013 clause
->AssignAttributeValue("corner", &m_cornerRadius
);
1015 // In case we're reading an old file, set the region's size
1016 if (m_regions
.Number() == 1)
1018 wxShapeRegion
*region
= (wxShapeRegion
*)m_regions
.First()->Data();
1019 region
->SetSize(m_width
, m_height
);
1024 void wxRectangleShape::Copy(wxShape
& copy
)
1026 wxShape::Copy(copy
);
1028 wxASSERT( copy
.IsKindOf(CLASSINFO(wxRectangleShape
)) );
1030 wxRectangleShape
& rectCopy
= (wxRectangleShape
&) copy
;
1031 rectCopy
.m_width
= m_width
;
1032 rectCopy
.m_height
= m_height
;
1033 rectCopy
.m_cornerRadius
= m_cornerRadius
;
1036 int wxRectangleShape::GetNumberOfAttachments()
1038 return wxShape::GetNumberOfAttachments();
1041 // There are 4 attachment points on a rectangle - 0 = top, 1 = right, 2 = bottom,
1043 bool wxRectangleShape::GetAttachmentPosition(int attachment
, float *x
, float *y
,
1044 int nth
, int no_arcs
, wxLineShape
*line
)
1046 if (m_attachmentMode
)
1048 float top
= (float)(m_ypos
+ m_height
/2.0);
1049 float bottom
= (float)(m_ypos
- m_height
/2.0);
1050 float left
= (float)(m_xpos
- m_width
/2.0);
1051 float right
= (float)(m_xpos
+ m_width
/2.0);
1053 bool isEnd
= (line
&& line
->IsEnd(this));
1059 if (m_spaceAttachments
)
1061 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
1063 // Align line according to the next handle along
1064 wxRealPoint
*point
= line
->GetNextControlPoint(this);
1065 if (point
->x
< left
)
1067 else if (point
->x
> right
)
1073 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
1083 if (m_spaceAttachments
)
1085 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
1087 // Align line according to the next handle along
1088 wxRealPoint
*point
= line
->GetNextControlPoint(this);
1089 if (point
->y
< bottom
)
1091 else if (point
->y
> top
)
1097 *y
= bottom
+ (nth
+ 1)*m_height
/(no_arcs
+ 1);
1104 if (m_spaceAttachments
)
1106 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
1108 // Align line according to the next handle along
1109 wxRealPoint
*point
= line
->GetNextControlPoint(this);
1110 if (point
->x
< left
)
1112 else if (point
->x
> right
)
1118 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
1127 if (m_spaceAttachments
)
1129 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
1131 // Align line according to the next handle along
1132 wxRealPoint
*point
= line
->GetNextControlPoint(this);
1133 if (point
->y
< bottom
)
1135 else if (point
->y
> top
)
1141 *y
= bottom
+ (nth
+ 1)*m_height
/(no_arcs
+ 1);
1148 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
1155 { *x
= m_xpos
; *y
= m_ypos
; return TRUE
; }
1158 // Text object (no box)
1160 IMPLEMENT_DYNAMIC_CLASS(wxTextShape
, wxRectangleShape
)
1162 wxTextShape::wxTextShape(float width
, float height
):
1163 wxRectangleShape(width
, height
)
1167 void wxTextShape::OnDraw(wxDC
& dc
)
1171 void wxTextShape::Copy(wxShape
& copy
)
1173 wxRectangleShape::Copy(copy
);
1177 void wxTextShape::WritePrologAttributes(wxExpr
*clause
)
1179 wxRectangleShape::WritePrologAttributes(clause
);
1185 IMPLEMENT_DYNAMIC_CLASS(wxEllipseShape
, wxShape
)
1187 wxEllipseShape::wxEllipseShape(float w
, float h
)
1189 m_width
= w
; m_height
= h
;
1190 SetDefaultRegionSize();
1193 void wxEllipseShape::GetBoundingBoxMin(float *w
, float *h
)
1195 *w
= m_width
; *h
= m_height
;
1198 bool wxEllipseShape::GetPerimeterPoint(float x1
, float y1
,
1200 float *x3
, float *y3
)
1202 float bound_x
, bound_y
;
1203 GetBoundingBoxMax(&bound_x
, &bound_y
);
1205 // find_end_for_box(bound_x, bound_y, m_xpos, m_ypos, x2, y2, x3, y3);
1206 draw_arc_to_ellipse(m_xpos
, m_ypos
, bound_x
, bound_y
, x2
, y2
, x1
, y1
, x3
, y3
);
1211 void wxEllipseShape::OnDraw(wxDC
& dc
)
1213 if (m_shadowMode
!= SHADOW_NONE
)
1216 dc
.SetBrush(m_shadowBrush
);
1217 dc
.SetPen(transparent_pen
);
1218 dc
.DrawEllipse((m_xpos
- GetWidth()/2) + m_shadowOffsetX
,
1219 (m_ypos
- GetHeight()/2) + m_shadowOffsetY
,
1220 GetWidth(), GetHeight());
1225 if (m_pen
->GetWidth() == 0)
1226 dc
.SetPen(transparent_pen
);
1231 dc
.SetBrush(m_brush
);
1232 dc
.DrawEllipse((m_xpos
- GetWidth()/2), (m_ypos
- GetHeight()/2), GetWidth(), GetHeight());
1235 void wxEllipseShape::SetSize(float x
, float y
, bool recursive
)
1237 SetAttachmentSize(x
, y
);
1240 SetDefaultRegionSize();
1244 void wxEllipseShape::WritePrologAttributes(wxExpr
*clause
)
1246 wxShape::WritePrologAttributes(clause
);
1247 clause
->AddAttributeValue("x", m_xpos
);
1248 clause
->AddAttributeValue("y", m_ypos
);
1250 clause
->AddAttributeValue("width", m_width
);
1251 clause
->AddAttributeValue("height", m_height
);
1254 void wxEllipseShape::ReadPrologAttributes(wxExpr
*clause
)
1256 wxShape::ReadPrologAttributes(clause
);
1257 clause
->AssignAttributeValue("width", &m_width
);
1258 clause
->AssignAttributeValue("height", &m_height
);
1260 // In case we're reading an old file, set the region's size
1261 if (m_regions
.Number() == 1)
1263 wxShapeRegion
*region
= (wxShapeRegion
*)m_regions
.First()->Data();
1264 region
->SetSize(m_width
, m_height
);
1269 void wxEllipseShape::Copy(wxShape
& copy
)
1271 wxShape::Copy(copy
);
1273 wxASSERT( copy
.IsKindOf(CLASSINFO(wxEllipseShape
)) );
1275 wxEllipseShape
& ellipseCopy
= (wxEllipseShape
&) copy
;
1277 ellipseCopy
.m_width
= m_width
;
1278 ellipseCopy
.m_height
= m_height
;
1281 int wxEllipseShape::GetNumberOfAttachments()
1283 return wxShape::GetNumberOfAttachments();
1286 // There are 4 attachment points on an ellipse - 0 = top, 1 = right, 2 = bottom,
1288 bool wxEllipseShape::GetAttachmentPosition(int attachment
, float *x
, float *y
,
1289 int nth
, int no_arcs
, wxLineShape
*line
)
1291 if (m_attachmentMode
)
1293 float top
= (float)(m_ypos
+ m_height
/2.0);
1294 float bottom
= (float)(m_ypos
- m_height
/2.0);
1295 float left
= (float)(m_xpos
- m_width
/2.0);
1296 float right
= (float)(m_xpos
+ m_width
/2.0);
1301 if (m_spaceAttachments
)
1302 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
1305 // We now have the point on the bounding box: but get the point on the ellipse
1306 // by imagining a vertical line from (*x, m_ypos - m_height- 500) to (*x, m_ypos) intersecting
1308 draw_arc_to_ellipse(m_xpos
, m_ypos
, m_width
, m_height
, *x
, (float)(m_ypos
-m_height
-500), *x
, m_ypos
, x
, y
);
1314 if (m_spaceAttachments
)
1315 *y
= bottom
+ (nth
+ 1)*m_height
/(no_arcs
+ 1);
1317 draw_arc_to_ellipse(m_xpos
, m_ypos
, m_width
, m_height
, (float)(m_xpos
+m_width
+500), *y
, m_xpos
, *y
, x
, y
);
1322 if (m_spaceAttachments
)
1323 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
1326 draw_arc_to_ellipse(m_xpos
, m_ypos
, m_width
, m_height
, *x
, (float)(m_ypos
+m_height
+500), *x
, m_ypos
, x
, y
);
1332 if (m_spaceAttachments
)
1333 *y
= bottom
+ (nth
+ 1)*m_height
/(no_arcs
+ 1);
1335 draw_arc_to_ellipse(m_xpos
, m_ypos
, m_width
, m_height
, (float)(m_xpos
-m_width
-500), *y
, m_xpos
, *y
, x
, y
);
1340 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
1347 { *x
= m_xpos
; *y
= m_ypos
; return TRUE
; }
1352 IMPLEMENT_DYNAMIC_CLASS(wxCircleShape
, wxEllipseShape
)
1354 wxCircleShape::wxCircleShape(float diameter
):wxEllipseShape(diameter
, diameter
)
1358 void wxCircleShape::Copy(wxShape
& copy
)
1360 wxEllipseShape::Copy(copy
);
1363 bool wxCircleShape::GetPerimeterPoint(float x1
, float y1
,
1365 float *x3
, float *y3
)
1367 find_end_for_circle(m_width
/2,
1368 m_xpos
, m_ypos
, // Centre of circle
1369 x2
, y2
, // Other end of line
1377 float wxControlPoint::controlPointDragStartX
= 0.0;
1378 float wxControlPoint::controlPointDragStartY
= 0.0;
1379 float wxControlPoint::controlPointDragStartWidth
= 0.0;
1380 float wxControlPoint::controlPointDragStartHeight
= 0.0;
1381 float wxControlPoint::controlPointDragEndWidth
= 0.0;
1382 float wxControlPoint::controlPointDragEndHeight
= 0.0;
1383 float wxControlPoint::controlPointDragPosX
= 0.0;
1384 float wxControlPoint::controlPointDragPosY
= 0.0;
1386 IMPLEMENT_DYNAMIC_CLASS(wxControlPoint
, wxRectangleShape
)
1388 wxControlPoint::wxControlPoint(wxShapeCanvas
*theCanvas
, wxShape
*object
, float size
, float the_xoffset
, float the_yoffset
, int the_type
):wxRectangleShape(size
, size
)
1390 m_canvas
= theCanvas
;
1392 m_xoffset
= the_xoffset
;
1393 m_yoffset
= the_yoffset
;
1395 SetPen(black_foreground_pen
);
1396 SetBrush(wxBLACK_BRUSH
);
1399 m_eraseObject
= TRUE
;
1402 wxControlPoint::~wxControlPoint()
1406 // Don't even attempt to draw any text - waste of time!
1407 void wxControlPoint::OnDrawContents(wxDC
& dc
)
1411 void wxControlPoint::OnDraw(wxDC
& dc
)
1413 m_xpos
= m_shape
->GetX() + m_xoffset
;
1414 m_ypos
= m_shape
->GetY() + m_yoffset
;
1415 wxRectangleShape::OnDraw(dc
);
1418 void wxControlPoint::OnErase(wxDC
& dc
)
1420 wxRectangleShape::OnErase(dc
);
1423 // Implement resizing of canvas object
1424 void wxControlPoint::OnDragLeft(bool draw
, float x
, float y
, int keys
, int attachment
)
1426 m_shape
->GetEventHandler()->OnSizingDragLeft(this, draw
, x
, y
, keys
, attachment
);
1429 void wxControlPoint::OnBeginDragLeft(float x
, float y
, int keys
, int attachment
)
1431 m_shape
->GetEventHandler()->OnSizingBeginDragLeft(this, x
, y
, keys
, attachment
);
1434 void wxControlPoint::OnEndDragLeft(float x
, float y
, int keys
, int attachment
)
1436 m_shape
->GetEventHandler()->OnSizingEndDragLeft(this, x
, y
, keys
, attachment
);
1439 int wxControlPoint::GetNumberOfAttachments()
1444 bool wxControlPoint::GetAttachmentPosition(int attachment
, float *x
, float *y
,
1445 int nth
, int no_arcs
, wxLineShape
*line
)
1447 *x
= m_xpos
; *y
= m_ypos
;
1451 // Control points ('handles') redirect control to the actual shape, to make it easier
1452 // to override sizing behaviour.
1453 void wxShape::OnSizingDragLeft(wxControlPoint
* pt
, bool draw
, float x
, float y
, int keys
, int attachment
)
1457 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1459 wxClientDC
dc(GetCanvas());
1460 GetCanvas()->PrepareDC(dc
);
1462 dc
.SetLogicalFunction(wxXOR
);
1464 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1465 dc
.SetPen(dottedPen
);
1466 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1468 if (this->GetCentreResize())
1470 // Maintain the same centre point.
1471 float new_width
= (float)(2.0*fabs(x
- this->GetX()));
1472 float new_height
= (float)(2.0*fabs(y
- this->GetY()));
1474 // Constrain sizing according to what control point you're dragging
1475 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1476 new_height
= bound_y
;
1477 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1478 new_width
= bound_x
;
1479 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& (keys
& KEY_SHIFT
))
1480 new_height
= bound_y
*(new_width
/bound_x
);
1482 if (this->GetFixedWidth())
1483 new_width
= bound_x
;
1485 if (this->GetFixedHeight())
1486 new_height
= bound_y
;
1488 pt
->controlPointDragEndWidth
= new_width
;
1489 pt
->controlPointDragEndHeight
= new_height
;
1491 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1492 new_width
, new_height
);
1496 // Don't maintain the same centre point!
1497 float newX1
= wxMin(pt
->controlPointDragStartX
, x
);
1498 float newY1
= wxMin(pt
->controlPointDragStartY
, y
);
1499 float newX2
= wxMax(pt
->controlPointDragStartX
, x
);
1500 float newY2
= wxMax(pt
->controlPointDragStartY
, y
);
1501 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1503 newY1
= pt
->controlPointDragStartY
;
1504 newY2
= newY1
+ pt
->controlPointDragStartHeight
;
1506 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1508 newX1
= pt
->controlPointDragStartX
;
1509 newX2
= newX1
+ pt
->controlPointDragStartWidth
;
1511 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& (keys
& KEY_SHIFT
))
1513 float newH
= (float)((newX2
- newX1
)*(pt
->controlPointDragStartHeight
/pt
->controlPointDragStartWidth
));
1514 if (GetY() > pt
->controlPointDragStartY
)
1515 newY2
= (float)(newY1
+ newH
);
1517 newY1
= (float)(newY2
- newH
);
1519 float newWidth
= (float)(newX2
- newX1
);
1520 float newHeight
= (float)(newY2
- newY1
);
1522 pt
->controlPointDragPosX
= (float)(newX1
+ (newWidth
/2.0));
1523 pt
->controlPointDragPosY
= (float)(newY1
+ (newHeight
/2.0));
1524 if (this->GetFixedWidth())
1527 if (this->GetFixedHeight())
1528 newHeight
= bound_y
;
1530 pt
->controlPointDragEndWidth
= newWidth
;
1531 pt
->controlPointDragEndHeight
= newHeight
;
1532 this->GetEventHandler()->OnDrawOutline(dc
, pt
->controlPointDragPosX
, pt
->controlPointDragPosY
, newWidth
, newHeight
);
1536 void wxShape::OnSizingBeginDragLeft(wxControlPoint
* pt
, float x
, float y
, int keys
, int attachment
)
1538 m_canvas
->CaptureMouse();
1540 wxClientDC
dc(GetCanvas());
1541 GetCanvas()->PrepareDC(dc
);
1543 if (pt
->m_eraseObject
)
1546 dc
.SetLogicalFunction(wxXOR
);
1550 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1552 // Choose the 'opposite corner' of the object as the stationary
1553 // point in case this is non-centring resizing.
1554 if (pt
->GetX() < this->GetX())
1555 pt
->controlPointDragStartX
= (float)(this->GetX() + (bound_x
/2.0));
1557 pt
->controlPointDragStartX
= (float)(this->GetX() - (bound_x
/2.0));
1559 if (pt
->GetY() < this->GetY())
1560 pt
->controlPointDragStartY
= (float)(this->GetY() + (bound_y
/2.0));
1562 pt
->controlPointDragStartY
= (float)(this->GetY() - (bound_y
/2.0));
1564 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1565 pt
->controlPointDragStartY
= (float)(this->GetY() - (bound_y
/2.0));
1566 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1567 pt
->controlPointDragStartX
= (float)(this->GetX() - (bound_x
/2.0));
1569 // We may require the old width and height.
1570 pt
->controlPointDragStartWidth
= bound_x
;
1571 pt
->controlPointDragStartHeight
= bound_y
;
1573 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1574 dc
.SetPen(dottedPen
);
1575 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1577 if (this->GetCentreResize())
1579 float new_width
= (float)(2.0*fabs(x
- this->GetX()));
1580 float new_height
= (float)(2.0*fabs(y
- this->GetY()));
1582 // Constrain sizing according to what control point you're dragging
1583 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1584 new_height
= bound_y
;
1585 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1586 new_width
= bound_x
;
1587 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& (keys
& KEY_SHIFT
))
1588 new_height
= bound_y
*(new_width
/bound_x
);
1590 if (this->GetFixedWidth())
1591 new_width
= bound_x
;
1593 if (this->GetFixedHeight())
1594 new_height
= bound_y
;
1596 pt
->controlPointDragEndWidth
= new_width
;
1597 pt
->controlPointDragEndHeight
= new_height
;
1598 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1599 new_width
, new_height
);
1603 // Don't maintain the same centre point!
1604 float newX1
= wxMin(pt
->controlPointDragStartX
, x
);
1605 float newY1
= wxMin(pt
->controlPointDragStartY
, y
);
1606 float newX2
= wxMax(pt
->controlPointDragStartX
, x
);
1607 float newY2
= wxMax(pt
->controlPointDragStartY
, y
);
1608 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1610 newY1
= pt
->controlPointDragStartY
;
1611 newY2
= newY1
+ pt
->controlPointDragStartHeight
;
1613 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1615 newX1
= pt
->controlPointDragStartX
;
1616 newX2
= newX1
+ pt
->controlPointDragStartWidth
;
1618 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& (keys
& KEY_SHIFT
))
1620 float newH
= (float)((newX2
- newX1
)*(pt
->controlPointDragStartHeight
/pt
->controlPointDragStartWidth
));
1621 if (pt
->GetY() > pt
->controlPointDragStartY
)
1622 newY2
= (float)(newY1
+ newH
);
1624 newY1
= (float)(newY2
- newH
);
1626 float newWidth
= (float)(newX2
- newX1
);
1627 float newHeight
= (float)(newY2
- newY1
);
1629 pt
->controlPointDragPosX
= (float)(newX1
+ (newWidth
/2.0));
1630 pt
->controlPointDragPosY
= (float)(newY1
+ (newHeight
/2.0));
1631 if (this->GetFixedWidth())
1634 if (this->GetFixedHeight())
1635 newHeight
= bound_y
;
1637 pt
->controlPointDragEndWidth
= newWidth
;
1638 pt
->controlPointDragEndHeight
= newHeight
;
1639 this->GetEventHandler()->OnDrawOutline(dc
, pt
->controlPointDragPosX
, pt
->controlPointDragPosY
, newWidth
, newHeight
);
1643 void wxShape::OnSizingEndDragLeft(wxControlPoint
* pt
, float x
, float y
, int keys
, int attachment
)
1645 wxClientDC
dc(GetCanvas());
1646 GetCanvas()->PrepareDC(dc
);
1648 m_canvas
->ReleaseMouse();
1649 dc
.SetLogicalFunction(wxCOPY
);
1651 this->ResetControlPoints();
1653 if (!pt
->m_eraseObject
)
1656 this->SetSize(pt
->controlPointDragEndWidth
, pt
->controlPointDragEndHeight
);
1658 // The next operation could destroy this control point (it does for label objects,
1659 // via formatting the text), so save all values we're going to use, or
1660 // we'll be accessing garbage.
1661 wxShape
*theObject
= this;
1662 wxShapeCanvas
*theCanvas
= m_canvas
;
1663 bool eraseIt
= pt
->m_eraseObject
;
1665 if (theObject
->GetCentreResize())
1666 theObject
->Move(dc
, theObject
->GetX(), theObject
->GetY());
1668 theObject
->Move(dc
, pt
->controlPointDragPosX
, pt
->controlPointDragPosY
);
1671 theObject
->Show(TRUE
);
1673 // Recursively redraw links if we have a composite.
1674 if (theObject
->GetChildren().Number() > 0)
1675 theObject
->DrawLinks(dc
, -1, TRUE
);
1677 float width
, height
;
1678 theObject
->GetBoundingBoxMax(&width
, &height
);
1679 theObject
->GetEventHandler()->OnEndSize(width
, height
);
1681 if (!theCanvas
->GetQuickEditMode() && eraseIt
) theCanvas
->Redraw(dc
);
1686 // Polygon control points
1688 IMPLEMENT_DYNAMIC_CLASS(wxPolygonControlPoint
, wxControlPoint
)
1690 wxPolygonControlPoint::wxPolygonControlPoint(wxShapeCanvas
*theCanvas
, wxShape
*object
, float size
,
1691 wxRealPoint
*vertex
, float the_xoffset
, float the_yoffset
):
1692 wxControlPoint(theCanvas
, object
, size
, the_xoffset
, the_yoffset
, 0)
1694 m_polygonVertex
= vertex
;
1695 m_originalDistance
= 0.0;
1698 wxPolygonControlPoint::~wxPolygonControlPoint()
1702 // Implement resizing polygon or moving the vertex.
1703 void wxPolygonControlPoint::OnDragLeft(bool draw
, float x
, float y
, int keys
, int attachment
)
1705 m_shape
->GetEventHandler()->OnSizingDragLeft(this, draw
, x
, y
, keys
, attachment
);
1708 void wxPolygonControlPoint::OnBeginDragLeft(float x
, float y
, int keys
, int attachment
)
1710 m_shape
->GetEventHandler()->OnSizingBeginDragLeft(this, x
, y
, keys
, attachment
);
1713 void wxPolygonControlPoint::OnEndDragLeft(float x
, float y
, int keys
, int attachment
)
1715 m_shape
->GetEventHandler()->OnSizingEndDragLeft(this, x
, y
, keys
, attachment
);
1718 // Control points ('handles') redirect control to the actual shape, to make it easier
1719 // to override sizing behaviour.
1720 void wxPolygonShape::OnSizingDragLeft(wxControlPoint
* pt
, bool draw
, float x
, float y
, int keys
, int attachment
)
1722 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
1724 wxClientDC
dc(GetCanvas());
1725 GetCanvas()->PrepareDC(dc
);
1727 dc
.SetLogicalFunction(wxXOR
);
1729 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1730 dc
.SetPen(dottedPen
);
1731 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1735 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1737 float new_width = (float)(2.0*fabs(x - this->GetX()));
1738 float new_height = (float)(2.0*fabs(y - this->GetY()));
1740 float dist
= (float)sqrt((x
- this->GetX())*(x
- this->GetX()) +
1741 (y
- this->GetY())*(y
- this->GetY()));
1743 if (keys
& KEY_CTRL
)
1745 m_canvas
->Snap(&x
, &y
);
1748 ppt
->m_polygonVertex
->x
= x
- this->GetX();
1749 ppt
->m_polygonVertex
->y
= y
- this->GetY();
1752 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1753 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1757 float new_width
= (float)(dist
/ppt
->m_originalDistance
)*ppt
->m_originalSize
.x
;
1758 float new_height
= (float)(dist
/ppt
->m_originalDistance
)*ppt
->m_originalSize
.y
;
1760 // Non-recursive SetSize for speed
1761 this->SetSize(new_width
, new_height
, FALSE
);
1764 this->GetBoundingBoxMax(&w
, &h
);
1765 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(), w
, h
);
1768 void wxPolygonShape::OnSizingBeginDragLeft(wxControlPoint
* pt
, float x
, float y
, int keys
, int attachment
)
1770 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
1772 wxClientDC
dc(GetCanvas());
1773 GetCanvas()->PrepareDC(dc
);
1777 dc
.SetLogicalFunction(wxXOR
);
1781 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1783 float dist
= (float)sqrt((x
- this->GetX())*(x
- this->GetX()) +
1784 (y
- this->GetY())*(y
- this->GetY()));
1786 ppt
->m_originalDistance
= dist
;
1787 ppt
->m_originalSize
.x
= bound_x
;
1788 ppt
->m_originalSize
.y
= bound_y
;
1790 if (ppt
->m_originalDistance
== 0.0) ppt
->m_originalDistance
= (float) 0.0001;
1792 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1793 dc
.SetPen(dottedPen
);
1794 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1796 if (keys
& KEY_CTRL
)
1798 m_canvas
->Snap(&x
, &y
);
1801 ppt
->m_polygonVertex
->x
= x
- this->GetX();
1802 ppt
->m_polygonVertex
->y
= y
- this->GetY();
1805 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1806 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1810 float new_width
= (float)(dist
/ppt
->m_originalDistance
)*ppt
->m_originalSize
.x
;
1811 float new_height
= (float)(dist
/ppt
->m_originalDistance
)*ppt
->m_originalSize
.y
;
1813 // Non-recursive SetSize for speed
1814 this->SetSize(new_width
, new_height
, FALSE
);
1818 this->GetBoundingBoxMax(&w
, &h
);
1819 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(), w
, h
);
1821 m_canvas
->CaptureMouse();
1824 void wxPolygonShape::OnSizingEndDragLeft(wxControlPoint
* pt
, float x
, float y
, int keys
, int attachment
)
1826 wxClientDC
dc(GetCanvas());
1827 GetCanvas()->PrepareDC(dc
);
1829 m_canvas
->ReleaseMouse();
1830 dc
.SetLogicalFunction(wxCOPY
);
1832 // If we're changing shape, must reset the original points
1833 if (keys
& KEY_CTRL
)
1835 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1836 ((wxPolygonShape
*)this)->UpdateOriginalPoints();
1839 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1840 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1843 this->ResetControlPoints();
1844 this->Move(dc
, this->GetX(), this->GetY());
1845 if (!m_canvas
->GetQuickEditMode()) m_canvas
->Redraw(dc
);
1852 IMPLEMENT_DYNAMIC_CLASS(wxShapeRegion
, wxObject
)
1854 wxShapeRegion::wxShapeRegion()
1857 m_font
= g_oglNormalFont
;
1865 m_regionProportionX
= -1.0;
1866 m_regionProportionY
= -1.0;
1867 m_formatMode
= FORMAT_CENTRE_HORIZ
| FORMAT_CENTRE_VERT
;
1869 m_textColour
= "BLACK";
1870 m_penColour
= "BLACK";
1871 m_penStyle
= wxSOLID
;
1872 m_actualColourObject
= NULL
;
1873 m_actualPenObject
= NULL
;
1876 wxShapeRegion::wxShapeRegion(wxShapeRegion
& region
)
1878 m_regionText
= region
.m_regionText
;
1879 m_regionName
= region
.m_regionName
;
1880 m_textColour
= region
.m_textColour
;
1882 m_font
= region
.m_font
;
1883 m_minHeight
= region
.m_minHeight
;
1884 m_minWidth
= region
.m_minWidth
;
1885 m_width
= region
.m_width
;
1886 m_height
= region
.m_height
;
1890 m_regionProportionX
= region
.m_regionProportionX
;
1891 m_regionProportionY
= region
.m_regionProportionY
;
1892 m_formatMode
= region
.m_formatMode
;
1893 m_actualColourObject
= NULL
;
1894 m_actualPenObject
= NULL
;
1895 m_penStyle
= region
.m_penStyle
;
1896 m_penColour
= region
.m_penColour
;
1899 wxNode
*node
= region
.m_formattedText
.First();
1902 wxShapeTextLine
*line
= (wxShapeTextLine
*)node
->Data();
1903 wxShapeTextLine
*new_line
=
1904 new wxShapeTextLine(line
->GetX(), line
->GetY(), line
->GetText());
1905 m_formattedText
.Append(new_line
);
1906 node
= node
->Next();
1910 wxShapeRegion::~wxShapeRegion()
1915 void wxShapeRegion::ClearText()
1917 wxNode
*node
= m_formattedText
.First();
1920 wxShapeTextLine
*line
= (wxShapeTextLine
*)node
->Data();
1921 wxNode
*next
= node
->Next();
1928 void wxShapeRegion::SetFont(wxFont
*f
)
1933 void wxShapeRegion::SetMinSize(float w
, float h
)
1939 void wxShapeRegion::SetSize(float w
, float h
)
1945 void wxShapeRegion::SetPosition(float xp
, float yp
)
1951 void wxShapeRegion::SetProportions(float xp
, float yp
)
1953 m_regionProportionX
= xp
;
1954 m_regionProportionY
= yp
;
1957 void wxShapeRegion::SetFormatMode(int mode
)
1959 m_formatMode
= mode
;
1962 void wxShapeRegion::SetColour(const wxString
& col
)
1965 m_actualColourObject
= NULL
;
1968 wxColour
*wxShapeRegion::GetActualColourObject()
1970 if (!m_actualColourObject
)
1971 m_actualColourObject
= wxTheColourDatabase
->FindColour(GetColour());
1972 if (!m_actualColourObject
)
1973 m_actualColourObject
= wxBLACK
;
1974 return m_actualColourObject
;
1977 void wxShapeRegion::SetPenColour(const wxString
& col
)
1980 m_actualPenObject
= NULL
;
1983 // Returns NULL if the pen is invisible
1984 // (different to pen being transparent; indicates that
1985 // region boundary should not be drawn.)
1986 wxPen
*wxShapeRegion::GetActualPen()
1988 if (m_actualPenObject
)
1989 return m_actualPenObject
;
1991 if (!m_penColour
) return NULL
;
1992 if (m_penColour
== "Invisible")
1994 m_actualPenObject
= wxThePenList
->FindOrCreatePen(m_penColour
, 1, m_penStyle
);
1995 return m_actualPenObject
;