1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Basic OGL classes (2)
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "basicp.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
28 #include <wx/deprecated/wxexpr.h>
39 #include "wx/ogl/ogl.h"
42 // Control point types
43 // Rectangle and most other shapes
44 #define CONTROL_POINT_VERTICAL 1
45 #define CONTROL_POINT_HORIZONTAL 2
46 #define CONTROL_POINT_DIAGONAL 3
49 #define CONTROL_POINT_ENDPOINT_TO 4
50 #define CONTROL_POINT_ENDPOINT_FROM 5
51 #define CONTROL_POINT_LINE 6
53 // Two stage construction: need to call Create
54 IMPLEMENT_DYNAMIC_CLASS(wxPolygonShape
, wxShape
)
56 wxPolygonShape::wxPolygonShape()
59 m_originalPoints
= NULL
;
62 void wxPolygonShape::Create(wxList
*the_points
)
66 m_originalPoints
= the_points
;
68 // Duplicate the list of points
69 m_points
= new wxList
;
71 wxNode
*node
= the_points
->GetFirst();
74 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
75 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
76 m_points
->Append((wxObject
*) new_point
);
77 node
= node
->GetNext();
79 CalculateBoundingBox();
80 m_originalWidth
= m_boundWidth
;
81 m_originalHeight
= m_boundHeight
;
82 SetDefaultRegionSize();
85 wxPolygonShape::~wxPolygonShape()
90 void wxPolygonShape::ClearPoints()
94 wxNode
*node
= m_points
->GetFirst();
97 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
100 node
= m_points
->GetFirst();
105 if (m_originalPoints
)
107 wxNode
*node
= m_originalPoints
->GetFirst();
110 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
113 node
= m_originalPoints
->GetFirst();
115 delete m_originalPoints
;
116 m_originalPoints
= NULL
;
121 // Width and height. Centre of object is centre of box.
122 void wxPolygonShape::GetBoundingBoxMin(double *width
, double *height
)
124 *width
= m_boundWidth
;
125 *height
= m_boundHeight
;
128 void wxPolygonShape::CalculateBoundingBox()
130 // Calculate bounding box at construction (and presumably resize) time
132 double right
= -10000;
134 double bottom
= -10000;
136 wxNode
*node
= m_points
->GetFirst();
139 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
140 if (point
->x
< left
) left
= point
->x
;
141 if (point
->x
> right
) right
= point
->x
;
143 if (point
->y
< top
) top
= point
->y
;
144 if (point
->y
> bottom
) bottom
= point
->y
;
146 node
= node
->GetNext();
148 m_boundWidth
= right
- left
;
149 m_boundHeight
= bottom
- top
;
152 // Recalculates the centre of the polygon, and
153 // readjusts the point offsets accordingly.
154 // Necessary since the centre of the polygon
155 // is expected to be the real centre of the bounding
157 void wxPolygonShape::CalculatePolygonCentre()
160 double right
= -10000;
162 double bottom
= -10000;
164 wxNode
*node
= m_points
->GetFirst();
167 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
168 if (point
->x
< left
) left
= point
->x
;
169 if (point
->x
> right
) right
= point
->x
;
171 if (point
->y
< top
) top
= point
->y
;
172 if (point
->y
> bottom
) bottom
= point
->y
;
174 node
= node
->GetNext();
176 double bwidth
= right
- left
;
177 double bheight
= bottom
- top
;
179 double newCentreX
= (double)(left
+ (bwidth
/2.0));
180 double newCentreY
= (double)(top
+ (bheight
/2.0));
182 node
= m_points
->GetFirst();
185 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
186 point
->x
-= newCentreX
;
187 point
->y
-= newCentreY
;
188 node
= node
->GetNext();
190 m_xpos
+= newCentreX
;
191 m_ypos
+= newCentreY
;
194 bool PolylineHitTest(double n
, double xvec
[], double yvec
[],
195 double x1
, double y1
, double x2
, double y2
)
199 double lastx
= xvec
[0];
200 double lasty
= yvec
[0];
202 double min_ratio
= 1.0;
206 for (i
= 1; i
< n
; i
++)
208 oglCheckLineIntersection(x1
, y1
, x2
, y2
, lastx
, lasty
, xvec
[i
], yvec
[i
],
209 &line_ratio
, &other_ratio
);
210 if (line_ratio
!= 1.0)
215 if (line_ratio
< min_ratio
)
216 min_ratio
= line_ratio
;
219 // Do last (implicit) line if last and first doubles are not identical
220 if (!(xvec
[0] == lastx
&& yvec
[0] == lasty
))
222 oglCheckLineIntersection(x1
, y1
, x2
, y2
, lastx
, lasty
, xvec
[0], yvec
[0],
223 &line_ratio
, &other_ratio
);
224 if (line_ratio
!= 1.0)
231 bool wxPolygonShape::HitTest(double x
, double y
, int *attachment
, double *distance
)
233 // Imagine four lines radiating from this point. If all of these lines hit the polygon,
234 // we're inside it, otherwise we're not. Obviously we'd need more radiating lines
235 // to be sure of correct results for very strange (concave) shapes.
236 double endPointsX
[4];
237 double endPointsY
[4];
240 endPointsY
[0] = (double)(y
- 1000.0);
242 endPointsX
[1] = (double)(x
+ 1000.0);
246 endPointsY
[2] = (double)(y
+ 1000.0);
248 endPointsX
[3] = (double)(x
- 1000.0);
251 // Store polygon points in an array
252 int np
= m_points
->GetCount();
253 double *xpoints
= new double[np
];
254 double *ypoints
= new double[np
];
255 wxNode
*node
= m_points
->GetFirst();
259 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
260 xpoints
[i
] = point
->x
+ m_xpos
;
261 ypoints
[i
] = point
->y
+ m_ypos
;
262 node
= node
->GetNext();
266 // We assume it's inside the polygon UNLESS one or more
267 // lines don't hit the outline.
268 bool isContained
= TRUE
;
271 for (i
= 0; i
< noPoints
; i
++)
273 if (!PolylineHitTest(np
, xpoints
, ypoints
, x
, y
, endPointsX
[i
], endPointsY
[i
]))
278 ClipsErrorFunction("It's a hit!\n");
280 ClipsErrorFunction("No hit.\n");
288 int nearest_attachment
= 0;
290 // If a hit, check the attachment points within the object.
291 int n
= GetNumberOfAttachments();
292 double nearest
= 999999.0;
294 for (i
= 0; i
< n
; i
++)
297 if (GetAttachmentPositionEdge(i
, &xp
, &yp
))
299 double l
= (double)sqrt(((xp
- x
) * (xp
- x
)) +
300 ((yp
- y
) * (yp
- y
)));
304 nearest_attachment
= i
;
308 *attachment
= nearest_attachment
;
313 // Really need to be able to reset the shape! Otherwise, if the
314 // points ever go to zero, we've lost it, and can't resize.
315 void wxPolygonShape::SetSize(double new_width
, double new_height
, bool WXUNUSED(recursive
))
317 SetAttachmentSize(new_width
, new_height
);
319 // Multiply all points by proportion of new size to old size
320 double x_proportion
= (double)(fabs(new_width
/m_originalWidth
));
321 double y_proportion
= (double)(fabs(new_height
/m_originalHeight
));
323 wxNode
*node
= m_points
->GetFirst();
324 wxNode
*original_node
= m_originalPoints
->GetFirst();
325 while (node
&& original_node
)
327 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
328 wxRealPoint
*original_point
= (wxRealPoint
*)original_node
->GetData();
330 point
->x
= (original_point
->x
* x_proportion
);
331 point
->y
= (original_point
->y
* y_proportion
);
333 node
= node
->GetNext();
334 original_node
= original_node
->GetNext();
337 // CalculateBoundingBox();
338 m_boundWidth
= (double)fabs(new_width
);
339 m_boundHeight
= (double)fabs(new_height
);
340 SetDefaultRegionSize();
343 // Make the original points the same as the working points
344 void wxPolygonShape::UpdateOriginalPoints()
346 if (!m_originalPoints
) m_originalPoints
= new wxList
;
347 wxNode
*original_node
= m_originalPoints
->GetFirst();
348 while (original_node
)
350 wxNode
*next_node
= original_node
->GetNext();
351 wxRealPoint
*original_point
= (wxRealPoint
*)original_node
->GetData();
352 delete original_point
;
353 delete original_node
;
355 original_node
= next_node
;
358 wxNode
*node
= m_points
->GetFirst();
361 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
362 wxRealPoint
*original_point
= new wxRealPoint(point
->x
, point
->y
);
363 m_originalPoints
->Append((wxObject
*) original_point
);
365 node
= node
->GetNext();
367 CalculateBoundingBox();
368 m_originalWidth
= m_boundWidth
;
369 m_originalHeight
= m_boundHeight
;
372 void wxPolygonShape::AddPolygonPoint(int pos
)
374 wxNode
*node
= m_points
->Item(pos
);
375 if (!node
) node
= m_points
->GetFirst();
376 wxRealPoint
*firstPoint
= (wxRealPoint
*)node
->GetData();
378 wxNode
*node2
= m_points
->Item(pos
+ 1);
379 if (!node2
) node2
= m_points
->GetFirst();
380 wxRealPoint
*secondPoint
= (wxRealPoint
*)node2
->GetData();
382 double x
= (double)((secondPoint
->x
- firstPoint
->x
)/2.0 + firstPoint
->x
);
383 double y
= (double)((secondPoint
->y
- firstPoint
->y
)/2.0 + firstPoint
->y
);
384 wxRealPoint
*point
= new wxRealPoint(x
, y
);
386 if (pos
>= (int) (m_points
->GetCount() - 1))
387 m_points
->Append((wxObject
*) point
);
389 m_points
->Insert(node2
, (wxObject
*) point
);
391 UpdateOriginalPoints();
395 DeleteControlPoints();
400 void wxPolygonShape::DeletePolygonPoint(int pos
)
402 wxNode
*node
= m_points
->Item(pos
);
405 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
408 UpdateOriginalPoints();
411 DeleteControlPoints();
417 // Assume (x1, y1) is centre of box (most generally, line end at box)
418 bool wxPolygonShape::GetPerimeterPoint(double x1
, double y1
,
419 double x2
, double y2
,
420 double *x3
, double *y3
)
422 int n
= m_points
->GetCount();
424 // First check for situation where the line is vertical,
425 // and we would want to connect to a point on that vertical --
426 // oglFindEndForPolyline can't cope with this (the arrow
427 // gets drawn to the wrong place).
428 if ((m_attachmentMode
== ATTACHMENT_MODE_NONE
) && (x1
== x2
))
430 // Look for the point we'd be connecting to. This is
432 wxNode
*node
= m_points
->GetFirst();
435 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
438 if ((y2
> y1
) && (point
->y
> 0.0))
440 *x3
= point
->x
+ m_xpos
;
441 *y3
= point
->y
+ m_ypos
;
444 else if ((y2
< y1
) && (point
->y
< 0.0))
446 *x3
= point
->x
+ m_xpos
;
447 *y3
= point
->y
+ m_ypos
;
451 node
= node
->GetNext();
455 double *xpoints
= new double[n
];
456 double *ypoints
= new double[n
];
458 wxNode
*node
= m_points
->GetFirst();
462 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
463 xpoints
[i
] = point
->x
+ m_xpos
;
464 ypoints
[i
] = point
->y
+ m_ypos
;
465 node
= node
->GetNext();
469 oglFindEndForPolyline(n
, xpoints
, ypoints
,
470 x1
, y1
, x2
, y2
, x3
, y3
);
478 void wxPolygonShape::OnDraw(wxDC
& dc
)
480 int n
= m_points
->GetCount();
481 wxPoint
*intPoints
= new wxPoint
[n
];
483 for (i
= 0; i
< n
; i
++)
485 wxRealPoint
* point
= (wxRealPoint
*) m_points
->Item(i
)->GetData();
486 intPoints
[i
].x
= WXROUND(point
->x
);
487 intPoints
[i
].y
= WXROUND(point
->y
);
490 if (m_shadowMode
!= SHADOW_NONE
)
493 dc
.SetBrush(* m_shadowBrush
);
494 dc
.SetPen(* g_oglTransparentPen
);
496 dc
.DrawPolygon(n
, intPoints
, WXROUND(m_xpos
+ m_shadowOffsetX
), WXROUND(m_ypos
+ m_shadowOffsetY
));
501 if (m_pen
->GetWidth() == 0)
502 dc
.SetPen(* g_oglTransparentPen
);
507 dc
.SetBrush(* m_brush
);
508 dc
.DrawPolygon(n
, intPoints
, WXROUND(m_xpos
), WXROUND(m_ypos
));
513 void wxPolygonShape::OnDrawOutline(wxDC
& dc
, double x
, double y
, double w
, double h
)
515 dc
.SetBrush(* wxTRANSPARENT_BRUSH
);
516 // Multiply all points by proportion of new size to old size
517 double x_proportion
= (double)(fabs(w
/m_originalWidth
));
518 double y_proportion
= (double)(fabs(h
/m_originalHeight
));
520 int n
= m_originalPoints
->GetCount();
521 wxPoint
*intPoints
= new wxPoint
[n
];
523 for (i
= 0; i
< n
; i
++)
525 wxRealPoint
* point
= (wxRealPoint
*) m_originalPoints
->Item(i
)->GetData();
526 intPoints
[i
].x
= WXROUND(x_proportion
* point
->x
);
527 intPoints
[i
].y
= WXROUND(y_proportion
* point
->y
);
529 dc
.DrawPolygon(n
, intPoints
, WXROUND(x
), WXROUND(y
));
533 // Make as many control points as there are vertices.
534 void wxPolygonShape::MakeControlPoints()
536 wxNode
*node
= m_points
->GetFirst();
539 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
540 wxPolygonControlPoint
*control
= new wxPolygonControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
,
541 point
, point
->x
, point
->y
);
542 m_canvas
->AddShape(control
);
543 m_controlPoints
.Append(control
);
544 node
= node
->GetNext();
548 void wxPolygonShape::ResetControlPoints()
550 wxNode
*node
= m_points
->GetFirst();
551 wxNode
*controlPointNode
= m_controlPoints
.GetFirst();
552 while (node
&& controlPointNode
)
554 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
555 wxPolygonControlPoint
*controlPoint
= (wxPolygonControlPoint
*)controlPointNode
->GetData();
557 controlPoint
->m_xoffset
= point
->x
;
558 controlPoint
->m_yoffset
= point
->y
;
559 controlPoint
->m_polygonVertex
= point
;
561 node
= node
->GetNext();
562 controlPointNode
= controlPointNode
->GetNext();
568 void wxPolygonShape::WriteAttributes(wxExpr
*clause
)
570 wxShape::WriteAttributes(clause
);
572 clause
->AddAttributeValue(wxT("x"), m_xpos
);
573 clause
->AddAttributeValue(wxT("y"), m_ypos
);
575 // Make a list of lists for the coordinates
576 wxExpr
*list
= new wxExpr(wxExprList
);
577 wxNode
*node
= m_points
->GetFirst();
580 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
581 wxExpr
*point_list
= new wxExpr(wxExprList
);
582 wxExpr
*x_expr
= new wxExpr((double)point
->x
);
583 wxExpr
*y_expr
= new wxExpr((double)point
->y
);
585 point_list
->Append(x_expr
);
586 point_list
->Append(y_expr
);
587 list
->Append(point_list
);
589 node
= node
->GetNext();
591 clause
->AddAttributeValue(wxT("points"), list
);
593 // Save the original (unscaled) points
594 list
= new wxExpr(wxExprList
);
595 node
= m_originalPoints
->GetFirst();
598 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
599 wxExpr
*point_list
= new wxExpr(wxExprList
);
600 wxExpr
*x_expr
= new wxExpr((double) point
->x
);
601 wxExpr
*y_expr
= new wxExpr((double) point
->y
);
602 point_list
->Append(x_expr
);
603 point_list
->Append(y_expr
);
604 list
->Append(point_list
);
606 node
= node
->GetNext();
608 clause
->AddAttributeValue(wxT("m_originalPoints"), list
);
611 void wxPolygonShape::ReadAttributes(wxExpr
*clause
)
613 wxShape::ReadAttributes(clause
);
615 // Read a list of lists
616 m_points
= new wxList
;
617 m_originalPoints
= new wxList
;
619 wxExpr
*points_list
= NULL
;
620 clause
->AssignAttributeValue(wxT("points"), &points_list
);
622 // If no points_list, don't crash!! Assume a diamond instead.
623 double the_height
= 100.0;
624 double the_width
= 100.0;
627 wxRealPoint
*point
= new wxRealPoint(0.0, (-the_height
/2));
628 m_points
->Append((wxObject
*) point
);
630 point
= new wxRealPoint((the_width
/2), 0.0);
631 m_points
->Append((wxObject
*) point
);
633 point
= new wxRealPoint(0.0, (the_height
/2));
634 m_points
->Append((wxObject
*) point
);
636 point
= new wxRealPoint((-the_width
/2), 0.0);
637 m_points
->Append((wxObject
*) point
);
639 point
= new wxRealPoint(0.0, (-the_height
/2));
640 m_points
->Append((wxObject
*) point
);
644 wxExpr
*node
= points_list
->value
.first
;
648 wxExpr
*xexpr
= node
->value
.first
;
649 long x
= xexpr
->IntegerValue();
651 wxExpr
*yexpr
= xexpr
->next
;
652 long y
= yexpr
->IntegerValue();
654 wxRealPoint
*point
= new wxRealPoint((double)x
, (double)y
);
655 m_points
->Append((wxObject
*) point
);
662 clause
->AssignAttributeValue(wxT("m_originalPoints"), &points_list
);
664 // If no points_list, don't crash!! Assume a diamond instead.
667 wxRealPoint
*point
= new wxRealPoint(0.0, (-the_height
/2));
668 m_originalPoints
->Append((wxObject
*) point
);
670 point
= new wxRealPoint((the_width
/2), 0.0);
671 m_originalPoints
->Append((wxObject
*) point
);
673 point
= new wxRealPoint(0.0, (the_height
/2));
674 m_originalPoints
->Append((wxObject
*) point
);
676 point
= new wxRealPoint((-the_width
/2), 0.0);
677 m_originalPoints
->Append((wxObject
*) point
);
679 point
= new wxRealPoint(0.0, (-the_height
/2));
680 m_originalPoints
->Append((wxObject
*) point
);
682 m_originalWidth
= the_width
;
683 m_originalHeight
= the_height
;
687 wxExpr
*node
= points_list
->value
.first
;
690 double max_x
= -1000;
691 double max_y
= -1000;
694 wxExpr
*xexpr
= node
->value
.first
;
695 long x
= xexpr
->IntegerValue();
697 wxExpr
*yexpr
= xexpr
->next
;
698 long y
= yexpr
->IntegerValue();
700 wxRealPoint
*point
= new wxRealPoint((double)x
, (double)y
);
701 m_originalPoints
->Append((wxObject
*) point
);
714 m_originalWidth
= max_x
- min_x
;
715 m_originalHeight
= max_y
- min_y
;
718 CalculateBoundingBox();
722 void wxPolygonShape::Copy(wxShape
& copy
)
726 wxASSERT( copy
.IsKindOf(CLASSINFO(wxPolygonShape
)) );
728 wxPolygonShape
& polyCopy
= (wxPolygonShape
&) copy
;
730 polyCopy
.ClearPoints();
732 polyCopy
.m_points
= new wxList
;
733 polyCopy
.m_originalPoints
= new wxList
;
735 wxNode
*node
= m_points
->GetFirst();
738 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
739 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
740 polyCopy
.m_points
->Append((wxObject
*) new_point
);
741 node
= node
->GetNext();
743 node
= m_originalPoints
->GetFirst();
746 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
747 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
748 polyCopy
.m_originalPoints
->Append((wxObject
*) new_point
);
749 node
= node
->GetNext();
751 polyCopy
.m_boundWidth
= m_boundWidth
;
752 polyCopy
.m_boundHeight
= m_boundHeight
;
753 polyCopy
.m_originalWidth
= m_originalWidth
;
754 polyCopy
.m_originalHeight
= m_originalHeight
;
757 int wxPolygonShape::GetNumberOfAttachments() const
759 int maxN
= (m_points
? (m_points
->GetCount() - 1) : 0);
760 wxNode
*node
= m_attachmentPoints
.GetFirst();
763 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->GetData();
764 if (point
->m_id
> maxN
)
766 node
= node
->GetNext();
771 bool wxPolygonShape::GetAttachmentPosition(int attachment
, double *x
, double *y
,
772 int nth
, int no_arcs
, wxLineShape
*line
)
774 if ((m_attachmentMode
== ATTACHMENT_MODE_EDGE
) && m_points
&& attachment
< (int) m_points
->GetCount())
776 wxRealPoint
*point
= (wxRealPoint
*)m_points
->Item(attachment
)->GetData();
777 *x
= point
->x
+ m_xpos
;
778 *y
= point
->y
+ m_ypos
;
782 { return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
); }
785 bool wxPolygonShape::AttachmentIsValid(int attachment
) const
790 if ((attachment
>= 0) && (attachment
< (int) m_points
->GetCount()))
793 wxNode
*node
= m_attachmentPoints
.GetFirst();
796 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->GetData();
797 if (point
->m_id
== attachment
)
799 node
= node
->GetNext();
804 // Rotate about the given axis by the given amount in radians
805 void wxPolygonShape::Rotate(double x
, double y
, double theta
)
807 double actualTheta
= theta
-m_rotation
;
809 // Rotate attachment points
810 double sinTheta
= (double)sin(actualTheta
);
811 double cosTheta
= (double)cos(actualTheta
);
812 wxNode
*node
= m_attachmentPoints
.GetFirst();
815 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->GetData();
816 double x1
= point
->m_x
;
817 double y1
= point
->m_y
;
818 point
->m_x
= x1
*cosTheta
- y1
*sinTheta
+ x
*(1.0 - cosTheta
) + y
*sinTheta
;
819 point
->m_y
= x1
*sinTheta
+ y1
*cosTheta
+ y
*(1.0 - cosTheta
) + x
*sinTheta
;
820 node
= node
->GetNext();
823 node
= m_points
->GetFirst();
826 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
827 double x1
= point
->x
;
828 double y1
= point
->y
;
829 point
->x
= x1
*cosTheta
- y1
*sinTheta
+ x
*(1.0 - cosTheta
) + y
*sinTheta
;
830 point
->y
= x1
*sinTheta
+ y1
*cosTheta
+ y
*(1.0 - cosTheta
) + x
*sinTheta
;
831 node
= node
->GetNext();
833 node
= m_originalPoints
->GetFirst();
836 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
837 double x1
= point
->x
;
838 double y1
= point
->y
;
839 point
->x
= x1
*cosTheta
- y1
*sinTheta
+ x
*(1.0 - cosTheta
) + y
*sinTheta
;
840 point
->y
= x1
*sinTheta
+ y1
*cosTheta
+ y
*(1.0 - cosTheta
) + x
*sinTheta
;
841 node
= node
->GetNext();
846 CalculatePolygonCentre();
847 CalculateBoundingBox();
848 ResetControlPoints();
853 IMPLEMENT_DYNAMIC_CLASS(wxRectangleShape
, wxShape
)
855 wxRectangleShape::wxRectangleShape(double w
, double h
)
857 m_width
= w
; m_height
= h
; m_cornerRadius
= 0.0;
858 SetDefaultRegionSize();
861 void wxRectangleShape::OnDraw(wxDC
& dc
)
863 double x1
= (double)(m_xpos
- m_width
/2.0);
864 double y1
= (double)(m_ypos
- m_height
/2.0);
866 if (m_shadowMode
!= SHADOW_NONE
)
869 dc
.SetBrush(* m_shadowBrush
);
870 dc
.SetPen(* g_oglTransparentPen
);
872 if (m_cornerRadius
!= 0.0)
873 dc
.DrawRoundedRectangle(WXROUND(x1
+ m_shadowOffsetX
), WXROUND(y1
+ m_shadowOffsetY
),
874 WXROUND(m_width
), WXROUND(m_height
), m_cornerRadius
);
876 dc
.DrawRectangle(WXROUND(x1
+ m_shadowOffsetX
), WXROUND(y1
+ m_shadowOffsetY
), WXROUND(m_width
), WXROUND(m_height
));
881 if (m_pen
->GetWidth() == 0)
882 dc
.SetPen(* g_oglTransparentPen
);
887 dc
.SetBrush(* m_brush
);
889 if (m_cornerRadius
!= 0.0)
890 dc
.DrawRoundedRectangle(WXROUND(x1
), WXROUND(y1
), WXROUND(m_width
), WXROUND(m_height
), m_cornerRadius
);
892 dc
.DrawRectangle(WXROUND(x1
), WXROUND(y1
), WXROUND(m_width
), WXROUND(m_height
));
895 void wxRectangleShape::GetBoundingBoxMin(double *the_width
, double *the_height
)
897 *the_width
= m_width
;
898 *the_height
= m_height
;
901 void wxRectangleShape::SetSize(double x
, double y
, bool WXUNUSED(recursive
))
903 SetAttachmentSize(x
, y
);
904 m_width
= (double)wxMax(x
, 1.0);
905 m_height
= (double)wxMax(y
, 1.0);
906 SetDefaultRegionSize();
909 void wxRectangleShape::SetCornerRadius(double rad
)
911 m_cornerRadius
= rad
;
914 // Assume (x1, y1) is centre of box (most generally, line end at box)
915 bool wxRectangleShape::GetPerimeterPoint(double WXUNUSED(x1
), double WXUNUSED(y1
),
916 double x2
, double y2
,
917 double *x3
, double *y3
)
919 double bound_x
, bound_y
;
920 GetBoundingBoxMax(&bound_x
, &bound_y
);
921 oglFindEndForBox(bound_x
, bound_y
, m_xpos
, m_ypos
, x2
, y2
, x3
, y3
);
927 void wxRectangleShape::WriteAttributes(wxExpr
*clause
)
929 wxShape::WriteAttributes(clause
);
930 clause
->AddAttributeValue(wxT("x"), m_xpos
);
931 clause
->AddAttributeValue(wxT("y"), m_ypos
);
933 clause
->AddAttributeValue(wxT("width"), m_width
);
934 clause
->AddAttributeValue(wxT("height"), m_height
);
935 if (m_cornerRadius
!= 0.0)
936 clause
->AddAttributeValue(wxT("corner"), m_cornerRadius
);
939 void wxRectangleShape::ReadAttributes(wxExpr
*clause
)
941 wxShape::ReadAttributes(clause
);
942 clause
->AssignAttributeValue(wxT("width"), &m_width
);
943 clause
->AssignAttributeValue(wxT("height"), &m_height
);
944 clause
->AssignAttributeValue(wxT("corner"), &m_cornerRadius
);
946 // In case we're reading an old file, set the region's size
947 if (m_regions
.GetCount() == 1)
949 wxShapeRegion
*region
= (wxShapeRegion
*)m_regions
.GetFirst()->GetData();
950 region
->SetSize(m_width
, m_height
);
955 void wxRectangleShape::Copy(wxShape
& copy
)
959 wxASSERT( copy
.IsKindOf(CLASSINFO(wxRectangleShape
)) );
961 wxRectangleShape
& rectCopy
= (wxRectangleShape
&) copy
;
962 rectCopy
.m_width
= m_width
;
963 rectCopy
.m_height
= m_height
;
964 rectCopy
.m_cornerRadius
= m_cornerRadius
;
967 int wxRectangleShape::GetNumberOfAttachments() const
969 return wxShape::GetNumberOfAttachments();
973 // There are 4 attachment points on a rectangle - 0 = top, 1 = right, 2 = bottom,
975 bool wxRectangleShape::GetAttachmentPosition(int attachment
, double *x
, double *y
,
976 int nth
, int no_arcs
, wxLineShape
*line
)
978 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
981 // Text object (no box)
983 IMPLEMENT_DYNAMIC_CLASS(wxTextShape
, wxRectangleShape
)
985 wxTextShape::wxTextShape(double width
, double height
):
986 wxRectangleShape(width
, height
)
990 void wxTextShape::OnDraw(wxDC
& WXUNUSED(dc
))
994 void wxTextShape::Copy(wxShape
& copy
)
996 wxRectangleShape::Copy(copy
);
1000 void wxTextShape::WriteAttributes(wxExpr
*clause
)
1002 wxRectangleShape::WriteAttributes(clause
);
1008 IMPLEMENT_DYNAMIC_CLASS(wxEllipseShape
, wxShape
)
1010 wxEllipseShape::wxEllipseShape(double w
, double h
)
1012 m_width
= w
; m_height
= h
;
1013 SetDefaultRegionSize();
1016 void wxEllipseShape::GetBoundingBoxMin(double *w
, double *h
)
1018 *w
= m_width
; *h
= m_height
;
1021 bool wxEllipseShape::GetPerimeterPoint(double x1
, double y1
,
1022 double x2
, double y2
,
1023 double *x3
, double *y3
)
1025 double bound_x
, bound_y
;
1026 GetBoundingBoxMax(&bound_x
, &bound_y
);
1028 // oglFindEndForBox(bound_x, bound_y, m_xpos, m_ypos, x2, y2, x3, y3);
1029 oglDrawArcToEllipse(m_xpos
, m_ypos
, bound_x
, bound_y
, x2
, y2
, x1
, y1
, x3
, y3
);
1034 void wxEllipseShape::OnDraw(wxDC
& dc
)
1036 if (m_shadowMode
!= SHADOW_NONE
)
1039 dc
.SetBrush(* m_shadowBrush
);
1040 dc
.SetPen(* g_oglTransparentPen
);
1041 dc
.DrawEllipse((long) ((m_xpos
- GetWidth()/2) + m_shadowOffsetX
),
1042 (long) ((m_ypos
- GetHeight()/2) + m_shadowOffsetY
),
1043 (long) GetWidth(), (long) GetHeight());
1048 if (m_pen
->GetWidth() == 0)
1049 dc
.SetPen(* g_oglTransparentPen
);
1054 dc
.SetBrush(* m_brush
);
1055 dc
.DrawEllipse((long) (m_xpos
- GetWidth()/2), (long) (m_ypos
- GetHeight()/2), (long) GetWidth(), (long) GetHeight());
1058 void wxEllipseShape::SetSize(double x
, double y
, bool WXUNUSED(recursive
))
1060 SetAttachmentSize(x
, y
);
1063 SetDefaultRegionSize();
1067 void wxEllipseShape::WriteAttributes(wxExpr
*clause
)
1069 wxShape::WriteAttributes(clause
);
1070 clause
->AddAttributeValue(wxT("x"), m_xpos
);
1071 clause
->AddAttributeValue(wxT("y"), m_ypos
);
1073 clause
->AddAttributeValue(wxT("width"), m_width
);
1074 clause
->AddAttributeValue(wxT("height"), m_height
);
1077 void wxEllipseShape::ReadAttributes(wxExpr
*clause
)
1079 wxShape::ReadAttributes(clause
);
1080 clause
->AssignAttributeValue(wxT("width"), &m_width
);
1081 clause
->AssignAttributeValue(wxT("height"), &m_height
);
1083 // In case we're reading an old file, set the region's size
1084 if (m_regions
.GetCount() == 1)
1086 wxShapeRegion
*region
= (wxShapeRegion
*)m_regions
.GetFirst()->GetData();
1087 region
->SetSize(m_width
, m_height
);
1092 void wxEllipseShape::Copy(wxShape
& copy
)
1094 wxShape::Copy(copy
);
1096 wxASSERT( copy
.IsKindOf(CLASSINFO(wxEllipseShape
)) );
1098 wxEllipseShape
& ellipseCopy
= (wxEllipseShape
&) copy
;
1100 ellipseCopy
.m_width
= m_width
;
1101 ellipseCopy
.m_height
= m_height
;
1104 int wxEllipseShape::GetNumberOfAttachments() const
1106 return wxShape::GetNumberOfAttachments();
1109 // There are 4 attachment points on an ellipse - 0 = top, 1 = right, 2 = bottom,
1111 bool wxEllipseShape::GetAttachmentPosition(int attachment
, double *x
, double *y
,
1112 int nth
, int no_arcs
, wxLineShape
*line
)
1114 if (m_attachmentMode
== ATTACHMENT_MODE_BRANCHING
)
1115 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
1117 if (m_attachmentMode
!= ATTACHMENT_MODE_NONE
)
1119 double top
= (double)(m_ypos
+ m_height
/2.0);
1120 double bottom
= (double)(m_ypos
- m_height
/2.0);
1121 double left
= (double)(m_xpos
- m_width
/2.0);
1122 double right
= (double)(m_xpos
+ m_width
/2.0);
1124 int physicalAttachment
= LogicalToPhysicalAttachment(attachment
);
1126 switch (physicalAttachment
)
1130 if (m_spaceAttachments
)
1131 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
1134 // We now have the point on the bounding box: but get the point on the ellipse
1135 // by imagining a vertical line from (*x, m_ypos - m_height- 500) to (*x, m_ypos) intersecting
1137 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, *x
, (double)(m_ypos
-m_height
-500), *x
, m_ypos
, x
, y
);
1143 if (m_spaceAttachments
)
1144 *y
= bottom
+ (nth
+ 1)*m_height
/(no_arcs
+ 1);
1146 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, (double)(m_xpos
+m_width
+500), *y
, m_xpos
, *y
, x
, y
);
1151 if (m_spaceAttachments
)
1152 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
1155 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, *x
, (double)(m_ypos
+m_height
+500), *x
, m_ypos
, x
, y
);
1161 if (m_spaceAttachments
)
1162 *y
= bottom
+ (nth
+ 1)*m_height
/(no_arcs
+ 1);
1164 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, (double)(m_xpos
-m_width
-500), *y
, m_xpos
, *y
, x
, y
);
1169 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
1175 { *x
= m_xpos
; *y
= m_ypos
; return TRUE
; }
1180 IMPLEMENT_DYNAMIC_CLASS(wxCircleShape
, wxEllipseShape
)
1182 wxCircleShape::wxCircleShape(double diameter
):wxEllipseShape(diameter
, diameter
)
1184 SetMaintainAspectRatio(TRUE
);
1187 void wxCircleShape::Copy(wxShape
& copy
)
1189 wxEllipseShape::Copy(copy
);
1192 bool wxCircleShape::GetPerimeterPoint(double WXUNUSED(x1
), double WXUNUSED(y1
),
1193 double x2
, double y2
,
1194 double *x3
, double *y3
)
1196 oglFindEndForCircle(m_width
/2,
1197 m_xpos
, m_ypos
, // Centre of circle
1198 x2
, y2
, // Other end of line
1206 double wxControlPoint::sm_controlPointDragStartX
= 0.0;
1207 double wxControlPoint::sm_controlPointDragStartY
= 0.0;
1208 double wxControlPoint::sm_controlPointDragStartWidth
= 0.0;
1209 double wxControlPoint::sm_controlPointDragStartHeight
= 0.0;
1210 double wxControlPoint::sm_controlPointDragEndWidth
= 0.0;
1211 double wxControlPoint::sm_controlPointDragEndHeight
= 0.0;
1212 double wxControlPoint::sm_controlPointDragPosX
= 0.0;
1213 double wxControlPoint::sm_controlPointDragPosY
= 0.0;
1215 IMPLEMENT_DYNAMIC_CLASS(wxControlPoint
, wxRectangleShape
)
1217 wxControlPoint::wxControlPoint(wxShapeCanvas
*theCanvas
, wxShape
*object
, double size
, double the_xoffset
, double the_yoffset
, int the_type
):wxRectangleShape(size
, size
)
1219 m_canvas
= theCanvas
;
1221 m_xoffset
= the_xoffset
;
1222 m_yoffset
= the_yoffset
;
1224 SetPen(g_oglBlackForegroundPen
);
1225 SetBrush(wxBLACK_BRUSH
);
1228 m_eraseObject
= TRUE
;
1231 wxControlPoint::~wxControlPoint()
1235 // Don't even attempt to draw any text - waste of time!
1236 void wxControlPoint::OnDrawContents(wxDC
& WXUNUSED(dc
))
1240 void wxControlPoint::OnDraw(wxDC
& dc
)
1242 m_xpos
= m_shape
->GetX() + m_xoffset
;
1243 m_ypos
= m_shape
->GetY() + m_yoffset
;
1244 wxRectangleShape::OnDraw(dc
);
1247 void wxControlPoint::OnErase(wxDC
& dc
)
1249 wxRectangleShape::OnErase(dc
);
1252 // Implement resizing of canvas object
1253 void wxControlPoint::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
1255 m_shape
->GetEventHandler()->OnSizingDragLeft(this, draw
, x
, y
, keys
, attachment
);
1258 void wxControlPoint::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
1260 m_shape
->GetEventHandler()->OnSizingBeginDragLeft(this, x
, y
, keys
, attachment
);
1263 void wxControlPoint::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
1265 m_shape
->GetEventHandler()->OnSizingEndDragLeft(this, x
, y
, keys
, attachment
);
1268 int wxControlPoint::GetNumberOfAttachments() const
1273 bool wxControlPoint::GetAttachmentPosition(int WXUNUSED(attachment
), double *x
, double *y
,
1274 int WXUNUSED(nth
), int WXUNUSED(no_arcs
), wxLineShape
*WXUNUSED(line
))
1276 *x
= m_xpos
; *y
= m_ypos
;
1280 // Control points ('handles') redirect control to the actual shape, to make it easier
1281 // to override sizing behaviour.
1282 void wxShape::OnSizingDragLeft(wxControlPoint
* pt
, bool WXUNUSED(draw
), double x
, double y
, int keys
, int WXUNUSED(attachment
))
1286 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1288 wxClientDC
dc(GetCanvas());
1289 GetCanvas()->PrepareDC(dc
);
1291 dc
.SetLogicalFunction(OGLRBLF
);
1293 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1294 dc
.SetPen(dottedPen
);
1295 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1297 if (this->GetCentreResize())
1299 // Maintain the same centre point.
1300 double new_width
= (double)(2.0*fabs(x
- this->GetX()));
1301 double new_height
= (double)(2.0*fabs(y
- this->GetY()));
1303 // Constrain sizing according to what control point you're dragging
1304 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1306 if (GetMaintainAspectRatio())
1308 new_height
= bound_y
*(new_width
/bound_x
);
1311 new_height
= bound_y
;
1313 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1315 if (GetMaintainAspectRatio())
1317 new_width
= bound_x
*(new_height
/bound_y
);
1320 new_width
= bound_x
;
1322 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& (keys
& KEY_SHIFT
))
1323 new_height
= bound_y
*(new_width
/bound_x
);
1325 if (this->GetFixedWidth())
1326 new_width
= bound_x
;
1328 if (this->GetFixedHeight())
1329 new_height
= bound_y
;
1331 pt
->sm_controlPointDragEndWidth
= new_width
;
1332 pt
->sm_controlPointDragEndHeight
= new_height
;
1334 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1335 new_width
, new_height
);
1339 // Don't maintain the same centre point!
1340 double newX1
= wxMin(pt
->sm_controlPointDragStartX
, x
);
1341 double newY1
= wxMin(pt
->sm_controlPointDragStartY
, y
);
1342 double newX2
= wxMax(pt
->sm_controlPointDragStartX
, x
);
1343 double newY2
= wxMax(pt
->sm_controlPointDragStartY
, y
);
1344 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1346 newY1
= pt
->sm_controlPointDragStartY
;
1347 newY2
= newY1
+ pt
->sm_controlPointDragStartHeight
;
1349 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1351 newX1
= pt
->sm_controlPointDragStartX
;
1352 newX2
= newX1
+ pt
->sm_controlPointDragStartWidth
;
1354 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& ((keys
& KEY_SHIFT
) || GetMaintainAspectRatio()))
1356 double newH
= (double)((newX2
- newX1
)*(pt
->sm_controlPointDragStartHeight
/pt
->sm_controlPointDragStartWidth
));
1357 if (GetY() > pt
->sm_controlPointDragStartY
)
1358 newY2
= (double)(newY1
+ newH
);
1360 newY1
= (double)(newY2
- newH
);
1362 double newWidth
= (double)(newX2
- newX1
);
1363 double newHeight
= (double)(newY2
- newY1
);
1365 if (pt
->m_type
== CONTROL_POINT_VERTICAL
&& GetMaintainAspectRatio())
1367 newWidth
= bound_x
* (newHeight
/bound_y
) ;
1370 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
&& GetMaintainAspectRatio())
1372 newHeight
= bound_y
* (newWidth
/bound_x
) ;
1375 pt
->sm_controlPointDragPosX
= (double)(newX1
+ (newWidth
/2.0));
1376 pt
->sm_controlPointDragPosY
= (double)(newY1
+ (newHeight
/2.0));
1377 if (this->GetFixedWidth())
1380 if (this->GetFixedHeight())
1381 newHeight
= bound_y
;
1383 pt
->sm_controlPointDragEndWidth
= newWidth
;
1384 pt
->sm_controlPointDragEndHeight
= newHeight
;
1385 this->GetEventHandler()->OnDrawOutline(dc
, pt
->sm_controlPointDragPosX
, pt
->sm_controlPointDragPosY
, newWidth
, newHeight
);
1389 void wxShape::OnSizingBeginDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int WXUNUSED(attachment
))
1391 m_canvas
->CaptureMouse();
1393 wxClientDC
dc(GetCanvas());
1394 GetCanvas()->PrepareDC(dc
);
1396 if (pt->m_eraseObject)
1400 dc
.SetLogicalFunction(OGLRBLF
);
1404 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1406 // Choose the 'opposite corner' of the object as the stationary
1407 // point in case this is non-centring resizing.
1408 if (pt
->GetX() < this->GetX())
1409 pt
->sm_controlPointDragStartX
= (double)(this->GetX() + (bound_x
/2.0));
1411 pt
->sm_controlPointDragStartX
= (double)(this->GetX() - (bound_x
/2.0));
1413 if (pt
->GetY() < this->GetY())
1414 pt
->sm_controlPointDragStartY
= (double)(this->GetY() + (bound_y
/2.0));
1416 pt
->sm_controlPointDragStartY
= (double)(this->GetY() - (bound_y
/2.0));
1418 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1419 pt
->sm_controlPointDragStartY
= (double)(this->GetY() - (bound_y
/2.0));
1420 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1421 pt
->sm_controlPointDragStartX
= (double)(this->GetX() - (bound_x
/2.0));
1423 // We may require the old width and height.
1424 pt
->sm_controlPointDragStartWidth
= bound_x
;
1425 pt
->sm_controlPointDragStartHeight
= bound_y
;
1427 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1428 dc
.SetPen(dottedPen
);
1429 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1431 if (this->GetCentreResize())
1433 double new_width
= (double)(2.0*fabs(x
- this->GetX()));
1434 double new_height
= (double)(2.0*fabs(y
- this->GetY()));
1436 // Constrain sizing according to what control point you're dragging
1437 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1439 if (GetMaintainAspectRatio())
1441 new_height
= bound_y
*(new_width
/bound_x
);
1444 new_height
= bound_y
;
1446 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1448 if (GetMaintainAspectRatio())
1450 new_width
= bound_x
*(new_height
/bound_y
);
1453 new_width
= bound_x
;
1455 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& (keys
& KEY_SHIFT
))
1456 new_height
= bound_y
*(new_width
/bound_x
);
1458 if (this->GetFixedWidth())
1459 new_width
= bound_x
;
1461 if (this->GetFixedHeight())
1462 new_height
= bound_y
;
1464 pt
->sm_controlPointDragEndWidth
= new_width
;
1465 pt
->sm_controlPointDragEndHeight
= new_height
;
1466 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1467 new_width
, new_height
);
1471 // Don't maintain the same centre point!
1472 double newX1
= wxMin(pt
->sm_controlPointDragStartX
, x
);
1473 double newY1
= wxMin(pt
->sm_controlPointDragStartY
, y
);
1474 double newX2
= wxMax(pt
->sm_controlPointDragStartX
, x
);
1475 double newY2
= wxMax(pt
->sm_controlPointDragStartY
, y
);
1476 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1478 newY1
= pt
->sm_controlPointDragStartY
;
1479 newY2
= newY1
+ pt
->sm_controlPointDragStartHeight
;
1481 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1483 newX1
= pt
->sm_controlPointDragStartX
;
1484 newX2
= newX1
+ pt
->sm_controlPointDragStartWidth
;
1486 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& ((keys
& KEY_SHIFT
) || GetMaintainAspectRatio()))
1488 double newH
= (double)((newX2
- newX1
)*(pt
->sm_controlPointDragStartHeight
/pt
->sm_controlPointDragStartWidth
));
1489 if (pt
->GetY() > pt
->sm_controlPointDragStartY
)
1490 newY2
= (double)(newY1
+ newH
);
1492 newY1
= (double)(newY2
- newH
);
1494 double newWidth
= (double)(newX2
- newX1
);
1495 double newHeight
= (double)(newY2
- newY1
);
1497 if (pt
->m_type
== CONTROL_POINT_VERTICAL
&& GetMaintainAspectRatio())
1499 newWidth
= bound_x
* (newHeight
/bound_y
) ;
1502 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
&& GetMaintainAspectRatio())
1504 newHeight
= bound_y
* (newWidth
/bound_x
) ;
1507 pt
->sm_controlPointDragPosX
= (double)(newX1
+ (newWidth
/2.0));
1508 pt
->sm_controlPointDragPosY
= (double)(newY1
+ (newHeight
/2.0));
1509 if (this->GetFixedWidth())
1512 if (this->GetFixedHeight())
1513 newHeight
= bound_y
;
1515 pt
->sm_controlPointDragEndWidth
= newWidth
;
1516 pt
->sm_controlPointDragEndHeight
= newHeight
;
1517 this->GetEventHandler()->OnDrawOutline(dc
, pt
->sm_controlPointDragPosX
, pt
->sm_controlPointDragPosY
, newWidth
, newHeight
);
1521 void wxShape::OnSizingEndDragLeft(wxControlPoint
* pt
, double WXUNUSED(x
), double WXUNUSED(y
), int WXUNUSED(keys
), int WXUNUSED(attachment
))
1523 wxClientDC
dc(GetCanvas());
1524 GetCanvas()->PrepareDC(dc
);
1526 m_canvas
->ReleaseMouse();
1527 dc
.SetLogicalFunction(wxCOPY
);
1529 this->ResetControlPoints();
1533 if (!pt->m_eraseObject)
1537 this->SetSize(pt
->sm_controlPointDragEndWidth
, pt
->sm_controlPointDragEndHeight
);
1539 // The next operation could destroy this control point (it does for label objects,
1540 // via formatting the text), so save all values we're going to use, or
1541 // we'll be accessing garbage.
1542 wxShape
*theObject
= this;
1543 wxShapeCanvas
*theCanvas
= m_canvas
;
1544 bool eraseIt
= pt
->m_eraseObject
;
1546 if (theObject
->GetCentreResize())
1547 theObject
->Move(dc
, theObject
->GetX(), theObject
->GetY());
1549 theObject
->Move(dc
, pt
->sm_controlPointDragPosX
, pt
->sm_controlPointDragPosY
);
1553 theObject->Show(TRUE);
1556 // Recursively redraw links if we have a composite.
1557 if (theObject
->GetChildren().GetCount() > 0)
1558 theObject
->DrawLinks(dc
, -1, TRUE
);
1560 double width
, height
;
1561 theObject
->GetBoundingBoxMax(&width
, &height
);
1562 theObject
->GetEventHandler()->OnEndSize(width
, height
);
1564 if (!theCanvas
->GetQuickEditMode() && eraseIt
) theCanvas
->Redraw(dc
);
1569 // Polygon control points
1571 IMPLEMENT_DYNAMIC_CLASS(wxPolygonControlPoint
, wxControlPoint
)
1573 wxPolygonControlPoint::wxPolygonControlPoint(wxShapeCanvas
*theCanvas
, wxShape
*object
, double size
,
1574 wxRealPoint
*vertex
, double the_xoffset
, double the_yoffset
):
1575 wxControlPoint(theCanvas
, object
, size
, the_xoffset
, the_yoffset
, 0)
1577 m_polygonVertex
= vertex
;
1578 m_originalDistance
= 0.0;
1581 wxPolygonControlPoint::~wxPolygonControlPoint()
1585 // Calculate what new size would be, at end of resize
1586 void wxPolygonControlPoint::CalculateNewSize(double x
, double y
)
1590 GetShape()->GetBoundingBoxMin(&bound_x
, &bound_y
);
1592 double dist
= (double)sqrt((x
- m_shape
->GetX())*(x
- m_shape
->GetX()) +
1593 (y
- m_shape
->GetY())*(y
- m_shape
->GetY()));
1595 m_newSize
.x
= (double)(dist
/this->m_originalDistance
)*this->m_originalSize
.x
;
1596 m_newSize
.y
= (double)(dist
/this->m_originalDistance
)*this->m_originalSize
.y
;
1600 // Implement resizing polygon or moving the vertex.
1601 void wxPolygonControlPoint::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
1603 m_shape
->GetEventHandler()->OnSizingDragLeft(this, draw
, x
, y
, keys
, attachment
);
1606 void wxPolygonControlPoint::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
1608 m_shape
->GetEventHandler()->OnSizingBeginDragLeft(this, x
, y
, keys
, attachment
);
1611 void wxPolygonControlPoint::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
1613 m_shape
->GetEventHandler()->OnSizingEndDragLeft(this, x
, y
, keys
, attachment
);
1616 // Control points ('handles') redirect control to the actual shape, to make it easier
1617 // to override sizing behaviour.
1618 void wxPolygonShape::OnSizingDragLeft(wxControlPoint
* pt
, bool WXUNUSED(draw
), double x
, double y
, int WXUNUSED(keys
), int WXUNUSED(attachment
))
1620 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
1622 wxClientDC
dc(GetCanvas());
1623 GetCanvas()->PrepareDC(dc
);
1625 dc
.SetLogicalFunction(OGLRBLF
);
1627 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1628 dc
.SetPen(dottedPen
);
1629 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1631 #if 0 // keys & KEY_CTRL)
1633 // TODO: mend this code. Currently we rely on altering the
1634 // actual points, but we should assume we're not, as per
1635 // the normal sizing case.
1636 m_canvas
->Snap(&x
, &y
);
1639 ppt
->m_polygonVertex
->x
= x
- this->GetX();
1640 ppt
->m_polygonVertex
->y
= y
- this->GetY();
1643 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1644 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1648 ppt
->CalculateNewSize(x
, y
);
1652 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1653 ppt
->GetNewSize().x
, ppt
->GetNewSize().y
);
1656 void wxPolygonShape::OnSizingBeginDragLeft(wxControlPoint
* pt
, double x
, double y
, int WXUNUSED(keys
), int WXUNUSED(attachment
))
1658 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
1660 wxClientDC
dc(GetCanvas());
1661 GetCanvas()->PrepareDC(dc
);
1665 dc
.SetLogicalFunction(OGLRBLF
);
1669 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1671 double dist
= (double)sqrt((x
- this->GetX())*(x
- this->GetX()) +
1672 (y
- this->GetY())*(y
- this->GetY()));
1673 ppt
->m_originalDistance
= dist
;
1674 ppt
->m_originalSize
.x
= bound_x
;
1675 ppt
->m_originalSize
.y
= bound_y
;
1677 if (ppt
->m_originalDistance
== 0.0) ppt
->m_originalDistance
= (double) 0.0001;
1679 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1680 dc
.SetPen(dottedPen
);
1681 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1683 #if 0 // keys & KEY_CTRL)
1685 // TODO: mend this code. Currently we rely on altering the
1686 // actual points, but we should assume we're not, as per
1687 // the normal sizing case.
1688 m_canvas
->Snap(&x
, &y
);
1691 ppt
->m_polygonVertex
->x
= x
- this->GetX();
1692 ppt
->m_polygonVertex
->y
= y
- this->GetY();
1695 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1696 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1700 ppt
->CalculateNewSize(x
, y
);
1704 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1705 ppt
->GetNewSize().x
, ppt
->GetNewSize().y
);
1707 m_canvas
->CaptureMouse();
1710 void wxPolygonShape::OnSizingEndDragLeft(wxControlPoint
* pt
, double WXUNUSED(x
), double WXUNUSED(y
), int keys
, int WXUNUSED(attachment
))
1712 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
1714 wxClientDC
dc(GetCanvas());
1715 GetCanvas()->PrepareDC(dc
);
1717 m_canvas
->ReleaseMouse();
1718 dc
.SetLogicalFunction(wxCOPY
);
1720 // If we're changing shape, must reset the original points
1721 if (keys
& KEY_CTRL
)
1723 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1724 ((wxPolygonShape
*)this)->UpdateOriginalPoints();
1728 SetSize(ppt
->GetNewSize().x
, ppt
->GetNewSize().y
);
1731 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1732 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1735 this->ResetControlPoints();
1736 this->Move(dc
, this->GetX(), this->GetY());
1737 if (!m_canvas
->GetQuickEditMode()) m_canvas
->Redraw(dc
);
1744 IMPLEMENT_DYNAMIC_CLASS(wxShapeRegion
, wxObject
)
1746 wxShapeRegion::wxShapeRegion()
1748 m_regionText
= wxEmptyString
;
1749 m_font
= g_oglNormalFont
;
1757 m_regionProportionX
= -1.0;
1758 m_regionProportionY
= -1.0;
1759 m_formatMode
= FORMAT_CENTRE_HORIZ
| FORMAT_CENTRE_VERT
;
1760 m_regionName
= wxEmptyString
;
1761 m_textColour
= wxT("BLACK");
1762 m_penColour
= wxT("BLACK");
1763 m_penStyle
= wxSOLID
;
1764 m_actualColourObject
= NULL
;
1765 m_actualPenObject
= NULL
;
1768 wxShapeRegion::wxShapeRegion(wxShapeRegion
& region
)
1770 m_regionText
= region
.m_regionText
;
1771 m_regionName
= region
.m_regionName
;
1772 m_textColour
= region
.m_textColour
;
1774 m_font
= region
.m_font
;
1775 m_minHeight
= region
.m_minHeight
;
1776 m_minWidth
= region
.m_minWidth
;
1777 m_width
= region
.m_width
;
1778 m_height
= region
.m_height
;
1782 m_regionProportionX
= region
.m_regionProportionX
;
1783 m_regionProportionY
= region
.m_regionProportionY
;
1784 m_formatMode
= region
.m_formatMode
;
1785 m_actualColourObject
= NULL
;
1786 m_actualPenObject
= NULL
;
1787 m_penStyle
= region
.m_penStyle
;
1788 m_penColour
= region
.m_penColour
;
1791 wxNode
*node
= region
.m_formattedText
.GetFirst();
1794 wxShapeTextLine
*line
= (wxShapeTextLine
*)node
->GetData();
1795 wxShapeTextLine
*new_line
=
1796 new wxShapeTextLine(line
->GetX(), line
->GetY(), line
->GetText());
1797 m_formattedText
.Append(new_line
);
1798 node
= node
->GetNext();
1802 wxShapeRegion::~wxShapeRegion()
1807 void wxShapeRegion::ClearText()
1809 wxNode
*node
= m_formattedText
.GetFirst();
1812 wxShapeTextLine
*line
= (wxShapeTextLine
*)node
->GetData();
1813 wxNode
*next
= node
->GetNext();
1820 void wxShapeRegion::SetFont(wxFont
*f
)
1825 void wxShapeRegion::SetMinSize(double w
, double h
)
1831 void wxShapeRegion::SetSize(double w
, double h
)
1837 void wxShapeRegion::SetPosition(double xp
, double yp
)
1843 void wxShapeRegion::SetProportions(double xp
, double yp
)
1845 m_regionProportionX
= xp
;
1846 m_regionProportionY
= yp
;
1849 void wxShapeRegion::SetFormatMode(int mode
)
1851 m_formatMode
= mode
;
1854 void wxShapeRegion::SetColour(const wxString
& col
)
1857 m_actualColourObject
= NULL
;
1860 wxColour
*wxShapeRegion::GetActualColourObject()
1862 if (!m_actualColourObject
)
1863 m_actualColourObject
= wxTheColourDatabase
->FindColour(GetColour());
1864 if (!m_actualColourObject
)
1865 m_actualColourObject
= wxBLACK
;
1866 return m_actualColourObject
;
1869 void wxShapeRegion::SetPenColour(const wxString
& col
)
1872 m_actualPenObject
= NULL
;
1875 // Returns NULL if the pen is invisible
1876 // (different to pen being transparent; indicates that
1877 // region boundary should not be drawn.)
1878 wxPen
*wxShapeRegion::GetActualPen()
1880 if (m_actualPenObject
)
1881 return m_actualPenObject
;
1883 if (!m_penColour
) return NULL
;
1884 if (m_penColour
== wxT("Invisible"))
1886 m_actualPenObject
= wxThePenList
->FindOrCreatePen(m_penColour
, 1, m_penStyle
);
1887 return m_actualPenObject
;