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"
27 #include <wx/wxexpr.h>
43 #include <wx/ogl/basic.h>
44 #include <wx/ogl/basicp.h>
45 #include <wx/ogl/composit.h>
46 #include <wx/ogl/lines.h>
47 #include <wx/ogl/canvas.h>
48 #include <wx/ogl/divided.h>
49 #include <wx/ogl/misc.h>
51 // Control point types
52 // Rectangle and most other shapes
53 #define CONTROL_POINT_VERTICAL 1
54 #define CONTROL_POINT_HORIZONTAL 2
55 #define CONTROL_POINT_DIAGONAL 3
58 #define CONTROL_POINT_ENDPOINT_TO 4
59 #define CONTROL_POINT_ENDPOINT_FROM 5
60 #define CONTROL_POINT_LINE 6
62 // Two stage construction: need to call Create
63 IMPLEMENT_DYNAMIC_CLASS(wxPolygonShape
, wxShape
)
65 wxPolygonShape::wxPolygonShape()
68 m_originalPoints
= NULL
;
71 void wxPolygonShape::Create(wxList
*the_points
)
75 m_originalPoints
= the_points
;
77 // Duplicate the list of points
78 m_points
= new wxList
;
80 wxNode
*node
= the_points
->First();
83 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
84 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
85 m_points
->Append((wxObject
*) new_point
);
88 CalculateBoundingBox();
89 m_originalWidth
= m_boundWidth
;
90 m_originalHeight
= m_boundHeight
;
91 SetDefaultRegionSize();
94 wxPolygonShape::~wxPolygonShape()
99 void wxPolygonShape::ClearPoints()
103 wxNode
*node
= m_points
->First();
106 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
109 node
= m_points
->First();
114 if (m_originalPoints
)
116 wxNode
*node
= m_originalPoints
->First();
119 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
122 node
= m_originalPoints
->First();
124 delete m_originalPoints
;
125 m_originalPoints
= NULL
;
130 // Width and height. Centre of object is centre of box.
131 void wxPolygonShape::GetBoundingBoxMin(double *width
, double *height
)
133 *width
= m_boundWidth
;
134 *height
= m_boundHeight
;
137 void wxPolygonShape::CalculateBoundingBox()
139 // Calculate bounding box at construction (and presumably resize) time
141 double right
= -10000;
143 double bottom
= -10000;
145 wxNode
*node
= m_points
->First();
148 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
149 if (point
->x
< left
) left
= point
->x
;
150 if (point
->x
> right
) right
= point
->x
;
152 if (point
->y
< top
) top
= point
->y
;
153 if (point
->y
> bottom
) bottom
= point
->y
;
157 m_boundWidth
= right
- left
;
158 m_boundHeight
= bottom
- top
;
161 // Recalculates the centre of the polygon, and
162 // readjusts the point offsets accordingly.
163 // Necessary since the centre of the polygon
164 // is expected to be the real centre of the bounding
166 void wxPolygonShape::CalculatePolygonCentre()
169 double right
= -10000;
171 double bottom
= -10000;
173 wxNode
*node
= m_points
->First();
176 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
177 if (point
->x
< left
) left
= point
->x
;
178 if (point
->x
> right
) right
= point
->x
;
180 if (point
->y
< top
) top
= point
->y
;
181 if (point
->y
> bottom
) bottom
= point
->y
;
185 double bwidth
= right
- left
;
186 double bheight
= bottom
- top
;
188 double newCentreX
= (double)(left
+ (bwidth
/2.0));
189 double newCentreY
= (double)(top
+ (bheight
/2.0));
191 node
= m_points
->First();
194 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
195 point
->x
-= newCentreX
;
196 point
->y
-= newCentreY
;
199 m_xpos
+= newCentreX
;
200 m_ypos
+= newCentreY
;
203 bool PolylineHitTest(double n
, double xvec
[], double yvec
[],
204 double x1
, double y1
, double x2
, double y2
)
208 double lastx
= xvec
[0];
209 double lasty
= yvec
[0];
211 double min_ratio
= 1.0;
216 for (i
= 1; i
< n
; i
++)
218 oglCheckLineIntersection(x1
, y1
, x2
, y2
, lastx
, lasty
, xvec
[i
], yvec
[i
],
219 &line_ratio
, &other_ratio
);
220 if (line_ratio
!= 1.0)
222 // sprintf(buf, "Line ratio = %.2f, other ratio = %.2f\n", line_ratio, other_ratio);
223 // ClipsErrorFunction(buf);
227 if (line_ratio
< min_ratio
)
228 min_ratio
= line_ratio
;
231 // Do last (implicit) line if last and first doubles are not identical
232 if (!(xvec
[0] == lastx
&& yvec
[0] == lasty
))
234 oglCheckLineIntersection(x1
, y1
, x2
, y2
, lastx
, lasty
, xvec
[0], yvec
[0],
235 &line_ratio
, &other_ratio
);
236 if (line_ratio
!= 1.0)
238 // sprintf(buf, "Line ratio = %.2f, other ratio = %.2f\n", line_ratio, other_ratio);
239 // ClipsErrorFunction(buf);
241 if (line_ratio
< min_ratio
)
242 min_ratio
= line_ratio
;
244 // ClipsErrorFunction("\n");
248 bool wxPolygonShape::HitTest(double x
, double y
, int *attachment
, double *distance
)
250 // Imagine four lines radiating from this point. If all of these lines hit the polygon,
251 // we're inside it, otherwise we're not. Obviously we'd need more radiating lines
252 // to be sure of correct results for very strange (concave) shapes.
253 double endPointsX
[4];
254 double endPointsY
[4];
257 endPointsY
[0] = (double)(y
- 1000.0);
259 endPointsX
[1] = (double)(x
+ 1000.0);
263 endPointsY
[2] = (double)(y
+ 1000.0);
265 endPointsX
[3] = (double)(x
- 1000.0);
268 // Store polygon points in an array
269 int np
= m_points
->Number();
270 double *xpoints
= new double[np
];
271 double *ypoints
= new double[np
];
272 wxNode
*node
= m_points
->First();
276 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
277 xpoints
[i
] = point
->x
+ m_xpos
;
278 ypoints
[i
] = point
->y
+ m_ypos
;
283 // We assume it's inside the polygon UNLESS one or more
284 // lines don't hit the outline.
285 bool isContained
= TRUE
;
288 for (i
= 0; i
< noPoints
; i
++)
290 if (!PolylineHitTest(np
, xpoints
, ypoints
, x
, y
, endPointsX
[i
], endPointsY
[i
]))
295 ClipsErrorFunction("It's a hit!\n");
297 ClipsErrorFunction("No hit.\n");
305 int nearest_attachment
= 0;
307 // If a hit, check the attachment points within the object.
308 int n
= GetNumberOfAttachments();
309 double nearest
= 999999.0;
311 for (i
= 0; i
< n
; i
++)
314 if (GetAttachmentPositionEdge(i
, &xp
, &yp
))
316 double l
= (double)sqrt(((xp
- x
) * (xp
- x
)) +
317 ((yp
- y
) * (yp
- y
)));
321 nearest_attachment
= i
;
325 *attachment
= nearest_attachment
;
330 // Really need to be able to reset the shape! Otherwise, if the
331 // points ever go to zero, we've lost it, and can't resize.
332 void wxPolygonShape::SetSize(double new_width
, double new_height
, bool recursive
)
334 SetAttachmentSize(new_width
, new_height
);
336 // Multiply all points by proportion of new size to old size
337 double x_proportion
= (double)(fabs(new_width
/m_originalWidth
));
338 double y_proportion
= (double)(fabs(new_height
/m_originalHeight
));
340 wxNode
*node
= m_points
->First();
341 wxNode
*original_node
= m_originalPoints
->First();
342 while (node
&& original_node
)
344 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
345 wxRealPoint
*original_point
= (wxRealPoint
*)original_node
->Data();
347 point
->x
= (original_point
->x
* x_proportion
);
348 point
->y
= (original_point
->y
* y_proportion
);
351 original_node
= original_node
->Next();
354 // CalculateBoundingBox();
355 m_boundWidth
= (double)fabs(new_width
);
356 m_boundHeight
= (double)fabs(new_height
);
357 SetDefaultRegionSize();
360 // Make the original points the same as the working points
361 void wxPolygonShape::UpdateOriginalPoints()
363 if (!m_originalPoints
) m_originalPoints
= new wxList
;
364 wxNode
*original_node
= m_originalPoints
->First();
365 while (original_node
)
367 wxNode
*next_node
= original_node
->Next();
368 wxRealPoint
*original_point
= (wxRealPoint
*)original_node
->Data();
369 delete original_point
;
370 delete original_node
;
372 original_node
= next_node
;
375 wxNode
*node
= m_points
->First();
378 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
379 wxRealPoint
*original_point
= new wxRealPoint(point
->x
, point
->y
);
380 m_originalPoints
->Append((wxObject
*) original_point
);
384 CalculateBoundingBox();
385 m_originalWidth
= m_boundWidth
;
386 m_originalHeight
= m_boundHeight
;
389 void wxPolygonShape::AddPolygonPoint(int pos
)
391 wxNode
*node
= m_points
->Nth(pos
);
392 if (!node
) node
= m_points
->First();
393 wxRealPoint
*firstPoint
= (wxRealPoint
*)node
->Data();
395 wxNode
*node2
= m_points
->Nth(pos
+ 1);
396 if (!node2
) node2
= m_points
->First();
397 wxRealPoint
*secondPoint
= (wxRealPoint
*)node2
->Data();
399 double x
= (double)((secondPoint
->x
- firstPoint
->x
)/2.0 + firstPoint
->x
);
400 double y
= (double)((secondPoint
->y
- firstPoint
->y
)/2.0 + firstPoint
->y
);
401 wxRealPoint
*point
= new wxRealPoint(x
, y
);
403 if (pos
>= (m_points
->Number() - 1))
404 m_points
->Append((wxObject
*) point
);
406 m_points
->Insert(node2
, (wxObject
*) point
);
408 UpdateOriginalPoints();
412 DeleteControlPoints();
417 void wxPolygonShape::DeletePolygonPoint(int pos
)
419 wxNode
*node
= m_points
->Nth(pos
);
422 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
425 UpdateOriginalPoints();
428 DeleteControlPoints();
434 // Assume (x1, y1) is centre of box (most generally, line end at box)
435 bool wxPolygonShape::GetPerimeterPoint(double x1
, double y1
,
436 double x2
, double y2
,
437 double *x3
, double *y3
)
439 int n
= m_points
->Number();
441 // First check for situation where the line is vertical,
442 // and we would want to connect to a point on that vertical --
443 // oglFindEndForPolyline can't cope with this (the arrow
444 // gets drawn to the wrong place).
445 if ((m_attachmentMode
== ATTACHMENT_MODE_NONE
) && (x1
== x2
))
447 // Look for the point we'd be connecting to. This is
449 wxNode
*node
= m_points
->First();
452 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
455 if ((y2
> y1
) && (point
->y
> 0.0))
457 *x3
= point
->x
+ m_xpos
;
458 *y3
= point
->y
+ m_ypos
;
461 else if ((y2
< y1
) && (point
->y
< 0.0))
463 *x3
= point
->x
+ m_xpos
;
464 *y3
= point
->y
+ m_ypos
;
472 double *xpoints
= new double[n
];
473 double *ypoints
= new double[n
];
475 wxNode
*node
= m_points
->First();
479 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
480 xpoints
[i
] = point
->x
+ m_xpos
;
481 ypoints
[i
] = point
->y
+ m_ypos
;
486 oglFindEndForPolyline(n
, xpoints
, ypoints
,
487 x1
, y1
, x2
, y2
, x3
, y3
);
495 void wxPolygonShape::OnDraw(wxDC
& dc
)
497 int n
= m_points
->Number();
498 wxPoint
*intPoints
= new wxPoint
[n
];
500 for (i
= 0; i
< n
; i
++)
502 wxRealPoint
* point
= (wxRealPoint
*) m_points
->Nth(i
)->Data();
503 intPoints
[i
].x
= WXROUND(point
->x
);
504 intPoints
[i
].y
= WXROUND(point
->y
);
507 if (m_shadowMode
!= SHADOW_NONE
)
510 dc
.SetBrush(* m_shadowBrush
);
511 dc
.SetPen(* g_oglTransparentPen
);
513 dc
.DrawPolygon(n
, intPoints
, WXROUND(m_xpos
+ m_shadowOffsetX
), WXROUND(m_ypos
+ m_shadowOffsetY
));
518 if (m_pen
->GetWidth() == 0)
519 dc
.SetPen(* g_oglTransparentPen
);
524 dc
.SetBrush(* m_brush
);
525 dc
.DrawPolygon(n
, intPoints
, WXROUND(m_xpos
), WXROUND(m_ypos
));
530 void wxPolygonShape::OnDrawOutline(wxDC
& dc
, double x
, double y
, double w
, double h
)
532 dc
.SetBrush(* wxTRANSPARENT_BRUSH
);
533 // Multiply all points by proportion of new size to old size
534 double x_proportion
= (double)(fabs(w
/m_originalWidth
));
535 double y_proportion
= (double)(fabs(h
/m_originalHeight
));
537 int n
= m_originalPoints
->Number();
538 wxPoint
*intPoints
= new wxPoint
[n
];
540 for (i
= 0; i
< n
; i
++)
542 wxRealPoint
* point
= (wxRealPoint
*) m_originalPoints
->Nth(i
)->Data();
543 intPoints
[i
].x
= WXROUND(x_proportion
* point
->x
);
544 intPoints
[i
].y
= WXROUND(y_proportion
* point
->y
);
546 dc
.DrawPolygon(n
, intPoints
, WXROUND(x
), WXROUND(y
));
550 // Make as many control points as there are vertices.
551 void wxPolygonShape::MakeControlPoints()
553 wxNode
*node
= m_points
->First();
556 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
557 wxPolygonControlPoint
*control
= new wxPolygonControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
,
558 point
, point
->x
, point
->y
);
559 m_canvas
->AddShape(control
);
560 m_controlPoints
.Append(control
);
565 void wxPolygonShape::ResetControlPoints()
567 wxNode
*node
= m_points
->First();
568 wxNode
*controlPointNode
= m_controlPoints
.First();
569 while (node
&& controlPointNode
)
571 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
572 wxPolygonControlPoint
*controlPoint
= (wxPolygonControlPoint
*)controlPointNode
->Data();
574 controlPoint
->m_xoffset
= point
->x
;
575 controlPoint
->m_yoffset
= point
->y
;
576 controlPoint
->m_polygonVertex
= point
;
579 controlPointNode
= controlPointNode
->Next();
585 void wxPolygonShape::WriteAttributes(wxExpr
*clause
)
587 wxShape::WriteAttributes(clause
);
589 clause
->AddAttributeValue(wxT("x"), m_xpos
);
590 clause
->AddAttributeValue(wxT("y"), m_ypos
);
592 // Make a list of lists for the coordinates
593 wxExpr
*list
= new wxExpr(wxExprList
);
594 wxNode
*node
= m_points
->First();
597 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
598 wxExpr
*point_list
= new wxExpr(wxExprList
);
599 wxExpr
*x_expr
= new wxExpr((double)point
->x
);
600 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
);
608 clause
->AddAttributeValue(wxT("points"), list
);
610 // Save the original (unscaled) points
611 list
= new wxExpr(wxExprList
);
612 node
= m_originalPoints
->First();
615 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
616 wxExpr
*point_list
= new wxExpr(wxExprList
);
617 wxExpr
*x_expr
= new wxExpr((double) point
->x
);
618 wxExpr
*y_expr
= new wxExpr((double) point
->y
);
619 point_list
->Append(x_expr
);
620 point_list
->Append(y_expr
);
621 list
->Append(point_list
);
625 clause
->AddAttributeValue(wxT("m_originalPoints"), list
);
628 void wxPolygonShape::ReadAttributes(wxExpr
*clause
)
630 wxShape::ReadAttributes(clause
);
632 // Read a list of lists
633 m_points
= new wxList
;
634 m_originalPoints
= new wxList
;
636 wxExpr
*points_list
= NULL
;
637 clause
->AssignAttributeValue(wxT("points"), &points_list
);
639 // If no points_list, don't crash!! Assume a diamond instead.
640 double the_height
= 100.0;
641 double the_width
= 100.0;
644 wxRealPoint
*point
= new wxRealPoint(0.0, (-the_height
/2));
645 m_points
->Append((wxObject
*) point
);
647 point
= new wxRealPoint((the_width
/2), 0.0);
648 m_points
->Append((wxObject
*) point
);
650 point
= new wxRealPoint(0.0, (the_height
/2));
651 m_points
->Append((wxObject
*) point
);
653 point
= new wxRealPoint((-the_width
/2), 0.0);
654 m_points
->Append((wxObject
*) point
);
656 point
= new wxRealPoint(0.0, (-the_height
/2));
657 m_points
->Append((wxObject
*) point
);
661 wxExpr
*node
= points_list
->value
.first
;
665 wxExpr
*xexpr
= node
->value
.first
;
666 long x
= xexpr
->IntegerValue();
668 wxExpr
*yexpr
= xexpr
->next
;
669 long y
= yexpr
->IntegerValue();
671 wxRealPoint
*point
= new wxRealPoint((double)x
, (double)y
);
672 m_points
->Append((wxObject
*) point
);
679 clause
->AssignAttributeValue(wxT("m_originalPoints"), &points_list
);
681 // If no points_list, don't crash!! Assume a diamond instead.
684 wxRealPoint
*point
= new wxRealPoint(0.0, (-the_height
/2));
685 m_originalPoints
->Append((wxObject
*) point
);
687 point
= new wxRealPoint((the_width
/2), 0.0);
688 m_originalPoints
->Append((wxObject
*) point
);
690 point
= new wxRealPoint(0.0, (the_height
/2));
691 m_originalPoints
->Append((wxObject
*) point
);
693 point
= new wxRealPoint((-the_width
/2), 0.0);
694 m_originalPoints
->Append((wxObject
*) point
);
696 point
= new wxRealPoint(0.0, (-the_height
/2));
697 m_originalPoints
->Append((wxObject
*) point
);
699 m_originalWidth
= the_width
;
700 m_originalHeight
= the_height
;
704 wxExpr
*node
= points_list
->value
.first
;
707 double max_x
= -1000;
708 double max_y
= -1000;
711 wxExpr
*xexpr
= node
->value
.first
;
712 long x
= xexpr
->IntegerValue();
714 wxExpr
*yexpr
= xexpr
->next
;
715 long y
= yexpr
->IntegerValue();
717 wxRealPoint
*point
= new wxRealPoint((double)x
, (double)y
);
718 m_originalPoints
->Append((wxObject
*) point
);
731 m_originalWidth
= max_x
- min_x
;
732 m_originalHeight
= max_y
- min_y
;
735 CalculateBoundingBox();
739 void wxPolygonShape::Copy(wxShape
& copy
)
743 wxASSERT( copy
.IsKindOf(CLASSINFO(wxPolygonShape
)) );
745 wxPolygonShape
& polyCopy
= (wxPolygonShape
&) copy
;
747 polyCopy
.ClearPoints();
749 polyCopy
.m_points
= new wxList
;
750 polyCopy
.m_originalPoints
= new wxList
;
752 wxNode
*node
= m_points
->First();
755 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
756 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
757 polyCopy
.m_points
->Append((wxObject
*) new_point
);
760 node
= m_originalPoints
->First();
763 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
764 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
765 polyCopy
.m_originalPoints
->Append((wxObject
*) new_point
);
768 polyCopy
.m_boundWidth
= m_boundWidth
;
769 polyCopy
.m_boundHeight
= m_boundHeight
;
770 polyCopy
.m_originalWidth
= m_originalWidth
;
771 polyCopy
.m_originalHeight
= m_originalHeight
;
774 int wxPolygonShape::GetNumberOfAttachments() const
776 int maxN
= (m_points
? (m_points
->Number() - 1) : 0);
777 wxNode
*node
= m_attachmentPoints
.First();
780 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
781 if (point
->m_id
> maxN
)
788 bool wxPolygonShape::GetAttachmentPosition(int attachment
, double *x
, double *y
,
789 int nth
, int no_arcs
, wxLineShape
*line
)
791 if ((m_attachmentMode
== ATTACHMENT_MODE_EDGE
) && m_points
&& attachment
< m_points
->Number())
793 wxRealPoint
*point
= (wxRealPoint
*)m_points
->Nth(attachment
)->Data();
794 *x
= point
->x
+ m_xpos
;
795 *y
= point
->y
+ m_ypos
;
799 { return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
); }
802 bool wxPolygonShape::AttachmentIsValid(int attachment
)
807 if ((attachment
>= 0) && (attachment
< m_points
->Number()))
810 wxNode
*node
= m_attachmentPoints
.First();
813 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
814 if (point
->m_id
== attachment
)
821 // Rotate about the given axis by the given amount in radians
822 void wxPolygonShape::Rotate(double x
, double y
, double theta
)
824 double actualTheta
= theta
-m_rotation
;
826 // Rotate attachment points
827 double sinTheta
= (double)sin(actualTheta
);
828 double cosTheta
= (double)cos(actualTheta
);
829 wxNode
*node
= m_attachmentPoints
.First();
832 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
833 double x1
= point
->m_x
;
834 double y1
= point
->m_y
;
835 point
->m_x
= x1
*cosTheta
- y1
*sinTheta
+ x
*(1.0 - cosTheta
) + y
*sinTheta
;
836 point
->m_y
= x1
*sinTheta
+ y1
*cosTheta
+ y
*(1.0 - cosTheta
) + x
*sinTheta
;
840 node
= m_points
->First();
843 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
844 double x1
= point
->x
;
845 double y1
= point
->y
;
846 point
->x
= x1
*cosTheta
- y1
*sinTheta
+ x
*(1.0 - cosTheta
) + y
*sinTheta
;
847 point
->y
= x1
*sinTheta
+ y1
*cosTheta
+ y
*(1.0 - cosTheta
) + x
*sinTheta
;
850 node
= m_originalPoints
->First();
853 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
854 double x1
= point
->x
;
855 double y1
= point
->y
;
856 point
->x
= x1
*cosTheta
- y1
*sinTheta
+ x
*(1.0 - cosTheta
) + y
*sinTheta
;
857 point
->y
= x1
*sinTheta
+ y1
*cosTheta
+ y
*(1.0 - cosTheta
) + x
*sinTheta
;
863 CalculatePolygonCentre();
864 CalculateBoundingBox();
865 ResetControlPoints();
870 IMPLEMENT_DYNAMIC_CLASS(wxRectangleShape
, wxShape
)
872 wxRectangleShape::wxRectangleShape(double w
, double h
)
874 m_width
= w
; m_height
= h
; m_cornerRadius
= 0.0;
875 SetDefaultRegionSize();
878 void wxRectangleShape::OnDraw(wxDC
& dc
)
880 double x1
= (double)(m_xpos
- m_width
/2.0);
881 double y1
= (double)(m_ypos
- m_height
/2.0);
883 if (m_shadowMode
!= SHADOW_NONE
)
886 dc
.SetBrush(* m_shadowBrush
);
887 dc
.SetPen(* g_oglTransparentPen
);
889 if (m_cornerRadius
!= 0.0)
890 dc
.DrawRoundedRectangle(WXROUND(x1
+ m_shadowOffsetX
), WXROUND(y1
+ m_shadowOffsetY
),
891 WXROUND(m_width
), WXROUND(m_height
), m_cornerRadius
);
893 dc
.DrawRectangle(WXROUND(x1
+ m_shadowOffsetX
), WXROUND(y1
+ m_shadowOffsetY
), WXROUND(m_width
), WXROUND(m_height
));
898 if (m_pen
->GetWidth() == 0)
899 dc
.SetPen(* g_oglTransparentPen
);
904 dc
.SetBrush(* m_brush
);
906 if (m_cornerRadius
!= 0.0)
907 dc
.DrawRoundedRectangle(WXROUND(x1
), WXROUND(y1
), WXROUND(m_width
), WXROUND(m_height
), m_cornerRadius
);
909 dc
.DrawRectangle(WXROUND(x1
), WXROUND(y1
), WXROUND(m_width
), WXROUND(m_height
));
912 void wxRectangleShape::GetBoundingBoxMin(double *the_width
, double *the_height
)
914 *the_width
= m_width
;
915 *the_height
= m_height
;
918 void wxRectangleShape::SetSize(double x
, double y
, bool recursive
)
920 SetAttachmentSize(x
, y
);
921 m_width
= (double)wxMax(x
, 1.0);
922 m_height
= (double)wxMax(y
, 1.0);
923 SetDefaultRegionSize();
926 void wxRectangleShape::SetCornerRadius(double rad
)
928 m_cornerRadius
= rad
;
931 // Assume (x1, y1) is centre of box (most generally, line end at box)
932 bool wxRectangleShape::GetPerimeterPoint(double x1
, double y1
,
933 double x2
, double y2
,
934 double *x3
, double *y3
)
936 double bound_x
, bound_y
;
937 GetBoundingBoxMax(&bound_x
, &bound_y
);
938 oglFindEndForBox(bound_x
, bound_y
, m_xpos
, m_ypos
, x2
, y2
, x3
, y3
);
944 void wxRectangleShape::WriteAttributes(wxExpr
*clause
)
946 wxShape::WriteAttributes(clause
);
947 clause
->AddAttributeValue(wxT("x"), m_xpos
);
948 clause
->AddAttributeValue(wxT("y"), m_ypos
);
950 clause
->AddAttributeValue(wxT("width"), m_width
);
951 clause
->AddAttributeValue(wxT("height"), m_height
);
952 if (m_cornerRadius
!= 0.0)
953 clause
->AddAttributeValue(wxT("corner"), m_cornerRadius
);
956 void wxRectangleShape::ReadAttributes(wxExpr
*clause
)
958 wxShape::ReadAttributes(clause
);
959 clause
->AssignAttributeValue(wxT("width"), &m_width
);
960 clause
->AssignAttributeValue(wxT("height"), &m_height
);
961 clause
->AssignAttributeValue(wxT("corner"), &m_cornerRadius
);
963 // In case we're reading an old file, set the region's size
964 if (m_regions
.Number() == 1)
966 wxShapeRegion
*region
= (wxShapeRegion
*)m_regions
.First()->Data();
967 region
->SetSize(m_width
, m_height
);
972 void wxRectangleShape::Copy(wxShape
& copy
)
976 wxASSERT( copy
.IsKindOf(CLASSINFO(wxRectangleShape
)) );
978 wxRectangleShape
& rectCopy
= (wxRectangleShape
&) copy
;
979 rectCopy
.m_width
= m_width
;
980 rectCopy
.m_height
= m_height
;
981 rectCopy
.m_cornerRadius
= m_cornerRadius
;
984 int wxRectangleShape::GetNumberOfAttachments() const
986 return wxShape::GetNumberOfAttachments();
990 // There are 4 attachment points on a rectangle - 0 = top, 1 = right, 2 = bottom,
992 bool wxRectangleShape::GetAttachmentPosition(int attachment
, double *x
, double *y
,
993 int nth
, int no_arcs
, wxLineShape
*line
)
995 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
998 // Text object (no box)
1000 IMPLEMENT_DYNAMIC_CLASS(wxTextShape
, wxRectangleShape
)
1002 wxTextShape::wxTextShape(double width
, double height
):
1003 wxRectangleShape(width
, height
)
1007 void wxTextShape::OnDraw(wxDC
& dc
)
1011 void wxTextShape::Copy(wxShape
& copy
)
1013 wxRectangleShape::Copy(copy
);
1017 void wxTextShape::WriteAttributes(wxExpr
*clause
)
1019 wxRectangleShape::WriteAttributes(clause
);
1025 IMPLEMENT_DYNAMIC_CLASS(wxEllipseShape
, wxShape
)
1027 wxEllipseShape::wxEllipseShape(double w
, double h
)
1029 m_width
= w
; m_height
= h
;
1030 SetDefaultRegionSize();
1033 void wxEllipseShape::GetBoundingBoxMin(double *w
, double *h
)
1035 *w
= m_width
; *h
= m_height
;
1038 bool wxEllipseShape::GetPerimeterPoint(double x1
, double y1
,
1039 double x2
, double y2
,
1040 double *x3
, double *y3
)
1042 double bound_x
, bound_y
;
1043 GetBoundingBoxMax(&bound_x
, &bound_y
);
1045 // oglFindEndForBox(bound_x, bound_y, m_xpos, m_ypos, x2, y2, x3, y3);
1046 oglDrawArcToEllipse(m_xpos
, m_ypos
, bound_x
, bound_y
, x2
, y2
, x1
, y1
, x3
, y3
);
1051 void wxEllipseShape::OnDraw(wxDC
& dc
)
1053 if (m_shadowMode
!= SHADOW_NONE
)
1056 dc
.SetBrush(* m_shadowBrush
);
1057 dc
.SetPen(* g_oglTransparentPen
);
1058 dc
.DrawEllipse((long) ((m_xpos
- GetWidth()/2) + m_shadowOffsetX
),
1059 (long) ((m_ypos
- GetHeight()/2) + m_shadowOffsetY
),
1060 (long) GetWidth(), (long) GetHeight());
1065 if (m_pen
->GetWidth() == 0)
1066 dc
.SetPen(* g_oglTransparentPen
);
1071 dc
.SetBrush(* m_brush
);
1072 dc
.DrawEllipse((long) (m_xpos
- GetWidth()/2), (long) (m_ypos
- GetHeight()/2), (long) GetWidth(), (long) GetHeight());
1075 void wxEllipseShape::SetSize(double x
, double y
, bool recursive
)
1077 SetAttachmentSize(x
, y
);
1080 SetDefaultRegionSize();
1084 void wxEllipseShape::WriteAttributes(wxExpr
*clause
)
1086 wxShape::WriteAttributes(clause
);
1087 clause
->AddAttributeValue(wxT("x"), m_xpos
);
1088 clause
->AddAttributeValue(wxT("y"), m_ypos
);
1090 clause
->AddAttributeValue(wxT("width"), m_width
);
1091 clause
->AddAttributeValue(wxT("height"), m_height
);
1094 void wxEllipseShape::ReadAttributes(wxExpr
*clause
)
1096 wxShape::ReadAttributes(clause
);
1097 clause
->AssignAttributeValue(wxT("width"), &m_width
);
1098 clause
->AssignAttributeValue(wxT("height"), &m_height
);
1100 // In case we're reading an old file, set the region's size
1101 if (m_regions
.Number() == 1)
1103 wxShapeRegion
*region
= (wxShapeRegion
*)m_regions
.First()->Data();
1104 region
->SetSize(m_width
, m_height
);
1109 void wxEllipseShape::Copy(wxShape
& copy
)
1111 wxShape::Copy(copy
);
1113 wxASSERT( copy
.IsKindOf(CLASSINFO(wxEllipseShape
)) );
1115 wxEllipseShape
& ellipseCopy
= (wxEllipseShape
&) copy
;
1117 ellipseCopy
.m_width
= m_width
;
1118 ellipseCopy
.m_height
= m_height
;
1121 int wxEllipseShape::GetNumberOfAttachments() const
1123 return wxShape::GetNumberOfAttachments();
1126 // There are 4 attachment points on an ellipse - 0 = top, 1 = right, 2 = bottom,
1128 bool wxEllipseShape::GetAttachmentPosition(int attachment
, double *x
, double *y
,
1129 int nth
, int no_arcs
, wxLineShape
*line
)
1131 if (m_attachmentMode
== ATTACHMENT_MODE_BRANCHING
)
1132 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
1134 if (m_attachmentMode
!= ATTACHMENT_MODE_NONE
)
1136 double top
= (double)(m_ypos
+ m_height
/2.0);
1137 double bottom
= (double)(m_ypos
- m_height
/2.0);
1138 double left
= (double)(m_xpos
- m_width
/2.0);
1139 double right
= (double)(m_xpos
+ m_width
/2.0);
1141 int physicalAttachment
= LogicalToPhysicalAttachment(attachment
);
1143 switch (physicalAttachment
)
1147 if (m_spaceAttachments
)
1148 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
1151 // We now have the point on the bounding box: but get the point on the ellipse
1152 // by imagining a vertical line from (*x, m_ypos - m_height- 500) to (*x, m_ypos) intersecting
1154 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, *x
, (double)(m_ypos
-m_height
-500), *x
, m_ypos
, x
, y
);
1160 if (m_spaceAttachments
)
1161 *y
= bottom
+ (nth
+ 1)*m_height
/(no_arcs
+ 1);
1163 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, (double)(m_xpos
+m_width
+500), *y
, m_xpos
, *y
, x
, y
);
1168 if (m_spaceAttachments
)
1169 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
1172 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, *x
, (double)(m_ypos
+m_height
+500), *x
, m_ypos
, x
, y
);
1178 if (m_spaceAttachments
)
1179 *y
= bottom
+ (nth
+ 1)*m_height
/(no_arcs
+ 1);
1181 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, (double)(m_xpos
-m_width
-500), *y
, m_xpos
, *y
, x
, y
);
1186 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
1193 { *x
= m_xpos
; *y
= m_ypos
; return TRUE
; }
1198 IMPLEMENT_DYNAMIC_CLASS(wxCircleShape
, wxEllipseShape
)
1200 wxCircleShape::wxCircleShape(double diameter
):wxEllipseShape(diameter
, diameter
)
1202 SetMaintainAspectRatio(TRUE
);
1205 void wxCircleShape::Copy(wxShape
& copy
)
1207 wxEllipseShape::Copy(copy
);
1210 bool wxCircleShape::GetPerimeterPoint(double x1
, double y1
,
1211 double x2
, double y2
,
1212 double *x3
, double *y3
)
1214 oglFindEndForCircle(m_width
/2,
1215 m_xpos
, m_ypos
, // Centre of circle
1216 x2
, y2
, // Other end of line
1224 double wxControlPoint::sm_controlPointDragStartX
= 0.0;
1225 double wxControlPoint::sm_controlPointDragStartY
= 0.0;
1226 double wxControlPoint::sm_controlPointDragStartWidth
= 0.0;
1227 double wxControlPoint::sm_controlPointDragStartHeight
= 0.0;
1228 double wxControlPoint::sm_controlPointDragEndWidth
= 0.0;
1229 double wxControlPoint::sm_controlPointDragEndHeight
= 0.0;
1230 double wxControlPoint::sm_controlPointDragPosX
= 0.0;
1231 double wxControlPoint::sm_controlPointDragPosY
= 0.0;
1233 IMPLEMENT_DYNAMIC_CLASS(wxControlPoint
, wxRectangleShape
)
1235 wxControlPoint::wxControlPoint(wxShapeCanvas
*theCanvas
, wxShape
*object
, double size
, double the_xoffset
, double the_yoffset
, int the_type
):wxRectangleShape(size
, size
)
1237 m_canvas
= theCanvas
;
1239 m_xoffset
= the_xoffset
;
1240 m_yoffset
= the_yoffset
;
1242 SetPen(g_oglBlackForegroundPen
);
1243 SetBrush(wxBLACK_BRUSH
);
1246 m_eraseObject
= TRUE
;
1249 wxControlPoint::~wxControlPoint()
1253 // Don't even attempt to draw any text - waste of time!
1254 void wxControlPoint::OnDrawContents(wxDC
& dc
)
1258 void wxControlPoint::OnDraw(wxDC
& dc
)
1260 m_xpos
= m_shape
->GetX() + m_xoffset
;
1261 m_ypos
= m_shape
->GetY() + m_yoffset
;
1262 wxRectangleShape::OnDraw(dc
);
1265 void wxControlPoint::OnErase(wxDC
& dc
)
1267 wxRectangleShape::OnErase(dc
);
1270 // Implement resizing of canvas object
1271 void wxControlPoint::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
1273 m_shape
->GetEventHandler()->OnSizingDragLeft(this, draw
, x
, y
, keys
, attachment
);
1276 void wxControlPoint::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
1278 m_shape
->GetEventHandler()->OnSizingBeginDragLeft(this, x
, y
, keys
, attachment
);
1281 void wxControlPoint::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
1283 m_shape
->GetEventHandler()->OnSizingEndDragLeft(this, x
, y
, keys
, attachment
);
1286 int wxControlPoint::GetNumberOfAttachments() const
1291 bool wxControlPoint::GetAttachmentPosition(int attachment
, double *x
, double *y
,
1292 int nth
, int no_arcs
, wxLineShape
*line
)
1294 *x
= m_xpos
; *y
= m_ypos
;
1298 // Control points ('handles') redirect control to the actual shape, to make it easier
1299 // to override sizing behaviour.
1300 void wxShape::OnSizingDragLeft(wxControlPoint
* pt
, bool draw
, double x
, double y
, int keys
, int attachment
)
1304 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1306 wxClientDC
dc(GetCanvas());
1307 GetCanvas()->PrepareDC(dc
);
1309 dc
.SetLogicalFunction(OGLRBLF
);
1311 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1312 dc
.SetPen(dottedPen
);
1313 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1315 if (this->GetCentreResize())
1317 // Maintain the same centre point.
1318 double new_width
= (double)(2.0*fabs(x
- this->GetX()));
1319 double new_height
= (double)(2.0*fabs(y
- this->GetY()));
1321 // Constrain sizing according to what control point you're dragging
1322 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1324 if (GetMaintainAspectRatio())
1326 new_height
= bound_y
*(new_width
/bound_x
);
1329 new_height
= bound_y
;
1331 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1333 if (GetMaintainAspectRatio())
1335 new_width
= bound_x
*(new_height
/bound_y
);
1338 new_width
= bound_x
;
1340 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& (keys
& KEY_SHIFT
))
1341 new_height
= bound_y
*(new_width
/bound_x
);
1343 if (this->GetFixedWidth())
1344 new_width
= bound_x
;
1346 if (this->GetFixedHeight())
1347 new_height
= bound_y
;
1349 pt
->sm_controlPointDragEndWidth
= new_width
;
1350 pt
->sm_controlPointDragEndHeight
= new_height
;
1352 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1353 new_width
, new_height
);
1357 // Don't maintain the same centre point!
1358 double newX1
= wxMin(pt
->sm_controlPointDragStartX
, x
);
1359 double newY1
= wxMin(pt
->sm_controlPointDragStartY
, y
);
1360 double newX2
= wxMax(pt
->sm_controlPointDragStartX
, x
);
1361 double newY2
= wxMax(pt
->sm_controlPointDragStartY
, y
);
1362 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1364 newY1
= pt
->sm_controlPointDragStartY
;
1365 newY2
= newY1
+ pt
->sm_controlPointDragStartHeight
;
1367 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1369 newX1
= pt
->sm_controlPointDragStartX
;
1370 newX2
= newX1
+ pt
->sm_controlPointDragStartWidth
;
1372 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& ((keys
& KEY_SHIFT
) || GetMaintainAspectRatio()))
1374 double newH
= (double)((newX2
- newX1
)*(pt
->sm_controlPointDragStartHeight
/pt
->sm_controlPointDragStartWidth
));
1375 if (GetY() > pt
->sm_controlPointDragStartY
)
1376 newY2
= (double)(newY1
+ newH
);
1378 newY1
= (double)(newY2
- newH
);
1380 double newWidth
= (double)(newX2
- newX1
);
1381 double newHeight
= (double)(newY2
- newY1
);
1383 if (pt
->m_type
== CONTROL_POINT_VERTICAL
&& GetMaintainAspectRatio())
1385 newWidth
= bound_x
* (newHeight
/bound_y
) ;
1388 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
&& GetMaintainAspectRatio())
1390 newHeight
= bound_y
* (newWidth
/bound_x
) ;
1393 pt
->sm_controlPointDragPosX
= (double)(newX1
+ (newWidth
/2.0));
1394 pt
->sm_controlPointDragPosY
= (double)(newY1
+ (newHeight
/2.0));
1395 if (this->GetFixedWidth())
1398 if (this->GetFixedHeight())
1399 newHeight
= bound_y
;
1401 pt
->sm_controlPointDragEndWidth
= newWidth
;
1402 pt
->sm_controlPointDragEndHeight
= newHeight
;
1403 this->GetEventHandler()->OnDrawOutline(dc
, pt
->sm_controlPointDragPosX
, pt
->sm_controlPointDragPosY
, newWidth
, newHeight
);
1407 void wxShape::OnSizingBeginDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int attachment
)
1409 m_canvas
->CaptureMouse();
1411 wxClientDC
dc(GetCanvas());
1412 GetCanvas()->PrepareDC(dc
);
1414 if (pt->m_eraseObject)
1418 dc
.SetLogicalFunction(OGLRBLF
);
1422 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1424 // Choose the 'opposite corner' of the object as the stationary
1425 // point in case this is non-centring resizing.
1426 if (pt
->GetX() < this->GetX())
1427 pt
->sm_controlPointDragStartX
= (double)(this->GetX() + (bound_x
/2.0));
1429 pt
->sm_controlPointDragStartX
= (double)(this->GetX() - (bound_x
/2.0));
1431 if (pt
->GetY() < this->GetY())
1432 pt
->sm_controlPointDragStartY
= (double)(this->GetY() + (bound_y
/2.0));
1434 pt
->sm_controlPointDragStartY
= (double)(this->GetY() - (bound_y
/2.0));
1436 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1437 pt
->sm_controlPointDragStartY
= (double)(this->GetY() - (bound_y
/2.0));
1438 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1439 pt
->sm_controlPointDragStartX
= (double)(this->GetX() - (bound_x
/2.0));
1441 // We may require the old width and height.
1442 pt
->sm_controlPointDragStartWidth
= bound_x
;
1443 pt
->sm_controlPointDragStartHeight
= bound_y
;
1445 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1446 dc
.SetPen(dottedPen
);
1447 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1449 if (this->GetCentreResize())
1451 double new_width
= (double)(2.0*fabs(x
- this->GetX()));
1452 double new_height
= (double)(2.0*fabs(y
- this->GetY()));
1454 // Constrain sizing according to what control point you're dragging
1455 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1457 if (GetMaintainAspectRatio())
1459 new_height
= bound_y
*(new_width
/bound_x
);
1462 new_height
= bound_y
;
1464 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1466 if (GetMaintainAspectRatio())
1468 new_width
= bound_x
*(new_height
/bound_y
);
1471 new_width
= bound_x
;
1473 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& (keys
& KEY_SHIFT
))
1474 new_height
= bound_y
*(new_width
/bound_x
);
1476 if (this->GetFixedWidth())
1477 new_width
= bound_x
;
1479 if (this->GetFixedHeight())
1480 new_height
= bound_y
;
1482 pt
->sm_controlPointDragEndWidth
= new_width
;
1483 pt
->sm_controlPointDragEndHeight
= new_height
;
1484 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1485 new_width
, new_height
);
1489 // Don't maintain the same centre point!
1490 double newX1
= wxMin(pt
->sm_controlPointDragStartX
, x
);
1491 double newY1
= wxMin(pt
->sm_controlPointDragStartY
, y
);
1492 double newX2
= wxMax(pt
->sm_controlPointDragStartX
, x
);
1493 double newY2
= wxMax(pt
->sm_controlPointDragStartY
, y
);
1494 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1496 newY1
= pt
->sm_controlPointDragStartY
;
1497 newY2
= newY1
+ pt
->sm_controlPointDragStartHeight
;
1499 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1501 newX1
= pt
->sm_controlPointDragStartX
;
1502 newX2
= newX1
+ pt
->sm_controlPointDragStartWidth
;
1504 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& ((keys
& KEY_SHIFT
) || GetMaintainAspectRatio()))
1506 double newH
= (double)((newX2
- newX1
)*(pt
->sm_controlPointDragStartHeight
/pt
->sm_controlPointDragStartWidth
));
1507 if (pt
->GetY() > pt
->sm_controlPointDragStartY
)
1508 newY2
= (double)(newY1
+ newH
);
1510 newY1
= (double)(newY2
- newH
);
1512 double newWidth
= (double)(newX2
- newX1
);
1513 double newHeight
= (double)(newY2
- newY1
);
1515 if (pt
->m_type
== CONTROL_POINT_VERTICAL
&& GetMaintainAspectRatio())
1517 newWidth
= bound_x
* (newHeight
/bound_y
) ;
1520 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
&& GetMaintainAspectRatio())
1522 newHeight
= bound_y
* (newWidth
/bound_x
) ;
1525 pt
->sm_controlPointDragPosX
= (double)(newX1
+ (newWidth
/2.0));
1526 pt
->sm_controlPointDragPosY
= (double)(newY1
+ (newHeight
/2.0));
1527 if (this->GetFixedWidth())
1530 if (this->GetFixedHeight())
1531 newHeight
= bound_y
;
1533 pt
->sm_controlPointDragEndWidth
= newWidth
;
1534 pt
->sm_controlPointDragEndHeight
= newHeight
;
1535 this->GetEventHandler()->OnDrawOutline(dc
, pt
->sm_controlPointDragPosX
, pt
->sm_controlPointDragPosY
, newWidth
, newHeight
);
1539 void wxShape::OnSizingEndDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int attachment
)
1541 wxClientDC
dc(GetCanvas());
1542 GetCanvas()->PrepareDC(dc
);
1544 m_canvas
->ReleaseMouse();
1545 dc
.SetLogicalFunction(wxCOPY
);
1547 this->ResetControlPoints();
1551 if (!pt->m_eraseObject)
1555 this->SetSize(pt
->sm_controlPointDragEndWidth
, pt
->sm_controlPointDragEndHeight
);
1557 // The next operation could destroy this control point (it does for label objects,
1558 // via formatting the text), so save all values we're going to use, or
1559 // we'll be accessing garbage.
1560 wxShape
*theObject
= this;
1561 wxShapeCanvas
*theCanvas
= m_canvas
;
1562 bool eraseIt
= pt
->m_eraseObject
;
1564 if (theObject
->GetCentreResize())
1565 theObject
->Move(dc
, theObject
->GetX(), theObject
->GetY());
1567 theObject
->Move(dc
, pt
->sm_controlPointDragPosX
, pt
->sm_controlPointDragPosY
);
1571 theObject->Show(TRUE);
1574 // Recursively redraw links if we have a composite.
1575 if (theObject
->GetChildren().Number() > 0)
1576 theObject
->DrawLinks(dc
, -1, TRUE
);
1578 double width
, height
;
1579 theObject
->GetBoundingBoxMax(&width
, &height
);
1580 theObject
->GetEventHandler()->OnEndSize(width
, height
);
1582 if (!theCanvas
->GetQuickEditMode() && eraseIt
) theCanvas
->Redraw(dc
);
1587 // Polygon control points
1589 IMPLEMENT_DYNAMIC_CLASS(wxPolygonControlPoint
, wxControlPoint
)
1591 wxPolygonControlPoint::wxPolygonControlPoint(wxShapeCanvas
*theCanvas
, wxShape
*object
, double size
,
1592 wxRealPoint
*vertex
, double the_xoffset
, double the_yoffset
):
1593 wxControlPoint(theCanvas
, object
, size
, the_xoffset
, the_yoffset
, 0)
1595 m_polygonVertex
= vertex
;
1596 m_originalDistance
= 0.0;
1599 wxPolygonControlPoint::~wxPolygonControlPoint()
1603 // Calculate what new size would be, at end of resize
1604 void wxPolygonControlPoint::CalculateNewSize(double x
, double y
)
1608 GetShape()->GetBoundingBoxMin(&bound_x
, &bound_y
);
1610 double dist
= (double)sqrt((x
- m_shape
->GetX())*(x
- m_shape
->GetX()) +
1611 (y
- m_shape
->GetY())*(y
- m_shape
->GetY()));
1613 m_newSize
.x
= (double)(dist
/this->m_originalDistance
)*this->m_originalSize
.x
;
1614 m_newSize
.y
= (double)(dist
/this->m_originalDistance
)*this->m_originalSize
.y
;
1618 // Implement resizing polygon or moving the vertex.
1619 void wxPolygonControlPoint::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
1621 m_shape
->GetEventHandler()->OnSizingDragLeft(this, draw
, x
, y
, keys
, attachment
);
1624 void wxPolygonControlPoint::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
1626 m_shape
->GetEventHandler()->OnSizingBeginDragLeft(this, x
, y
, keys
, attachment
);
1629 void wxPolygonControlPoint::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
1631 m_shape
->GetEventHandler()->OnSizingEndDragLeft(this, x
, y
, keys
, attachment
);
1634 // Control points ('handles') redirect control to the actual shape, to make it easier
1635 // to override sizing behaviour.
1636 void wxPolygonShape::OnSizingDragLeft(wxControlPoint
* pt
, bool draw
, double x
, double y
, int keys
, int attachment
)
1638 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
1640 wxClientDC
dc(GetCanvas());
1641 GetCanvas()->PrepareDC(dc
);
1643 dc
.SetLogicalFunction(OGLRBLF
);
1645 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1646 dc
.SetPen(dottedPen
);
1647 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1649 if (0) // keys & KEY_CTRL)
1651 // TODO: mend this code. Currently we rely on altering the
1652 // actual points, but we should assume we're not, as per
1653 // the normal sizing case.
1654 m_canvas
->Snap(&x
, &y
);
1657 ppt
->m_polygonVertex
->x
= x
- this->GetX();
1658 ppt
->m_polygonVertex
->y
= y
- this->GetY();
1661 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1662 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1666 ppt
->CalculateNewSize(x
, y
);
1669 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1670 ppt
->GetNewSize().x
, ppt
->GetNewSize().y
);
1673 void wxPolygonShape::OnSizingBeginDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int attachment
)
1675 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
1677 wxClientDC
dc(GetCanvas());
1678 GetCanvas()->PrepareDC(dc
);
1682 dc
.SetLogicalFunction(OGLRBLF
);
1686 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1688 double dist
= (double)sqrt((x
- this->GetX())*(x
- this->GetX()) +
1689 (y
- this->GetY())*(y
- this->GetY()));
1690 ppt
->m_originalDistance
= dist
;
1691 ppt
->m_originalSize
.x
= bound_x
;
1692 ppt
->m_originalSize
.y
= bound_y
;
1694 if (ppt
->m_originalDistance
== 0.0) ppt
->m_originalDistance
= (double) 0.0001;
1696 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1697 dc
.SetPen(dottedPen
);
1698 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1700 if (0) // keys & KEY_CTRL)
1702 // TODO: mend this code. Currently we rely on altering the
1703 // actual points, but we should assume we're not, as per
1704 // the normal sizing case.
1705 m_canvas
->Snap(&x
, &y
);
1708 ppt
->m_polygonVertex
->x
= x
- this->GetX();
1709 ppt
->m_polygonVertex
->y
= y
- this->GetY();
1712 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1713 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1717 ppt
->CalculateNewSize(x
, y
);
1720 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1721 ppt
->GetNewSize().x
, ppt
->GetNewSize().y
);
1723 m_canvas
->CaptureMouse();
1726 void wxPolygonShape::OnSizingEndDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int attachment
)
1728 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
1730 wxClientDC
dc(GetCanvas());
1731 GetCanvas()->PrepareDC(dc
);
1733 m_canvas
->ReleaseMouse();
1734 dc
.SetLogicalFunction(wxCOPY
);
1736 // If we're changing shape, must reset the original points
1737 if (keys
& KEY_CTRL
)
1739 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1740 ((wxPolygonShape
*)this)->UpdateOriginalPoints();
1744 SetSize(ppt
->GetNewSize().x
, ppt
->GetNewSize().y
);
1747 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1748 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1751 this->ResetControlPoints();
1752 this->Move(dc
, this->GetX(), this->GetY());
1753 if (!m_canvas
->GetQuickEditMode()) m_canvas
->Redraw(dc
);
1760 IMPLEMENT_DYNAMIC_CLASS(wxShapeRegion
, wxObject
)
1762 wxShapeRegion::wxShapeRegion()
1765 m_font
= g_oglNormalFont
;
1773 m_regionProportionX
= -1.0;
1774 m_regionProportionY
= -1.0;
1775 m_formatMode
= FORMAT_CENTRE_HORIZ
| FORMAT_CENTRE_VERT
;
1777 m_textColour
= "BLACK";
1778 m_penColour
= "BLACK";
1779 m_penStyle
= wxSOLID
;
1780 m_actualColourObject
= NULL
;
1781 m_actualPenObject
= NULL
;
1784 wxShapeRegion::wxShapeRegion(wxShapeRegion
& region
)
1786 m_regionText
= region
.m_regionText
;
1787 m_regionName
= region
.m_regionName
;
1788 m_textColour
= region
.m_textColour
;
1790 m_font
= region
.m_font
;
1791 m_minHeight
= region
.m_minHeight
;
1792 m_minWidth
= region
.m_minWidth
;
1793 m_width
= region
.m_width
;
1794 m_height
= region
.m_height
;
1798 m_regionProportionX
= region
.m_regionProportionX
;
1799 m_regionProportionY
= region
.m_regionProportionY
;
1800 m_formatMode
= region
.m_formatMode
;
1801 m_actualColourObject
= NULL
;
1802 m_actualPenObject
= NULL
;
1803 m_penStyle
= region
.m_penStyle
;
1804 m_penColour
= region
.m_penColour
;
1807 wxNode
*node
= region
.m_formattedText
.First();
1810 wxShapeTextLine
*line
= (wxShapeTextLine
*)node
->Data();
1811 wxShapeTextLine
*new_line
=
1812 new wxShapeTextLine(line
->GetX(), line
->GetY(), line
->GetText());
1813 m_formattedText
.Append(new_line
);
1814 node
= node
->Next();
1818 wxShapeRegion::~wxShapeRegion()
1823 void wxShapeRegion::ClearText()
1825 wxNode
*node
= m_formattedText
.First();
1828 wxShapeTextLine
*line
= (wxShapeTextLine
*)node
->Data();
1829 wxNode
*next
= node
->Next();
1836 void wxShapeRegion::SetFont(wxFont
*f
)
1841 void wxShapeRegion::SetMinSize(double w
, double h
)
1847 void wxShapeRegion::SetSize(double w
, double h
)
1853 void wxShapeRegion::SetPosition(double xp
, double yp
)
1859 void wxShapeRegion::SetProportions(double xp
, double yp
)
1861 m_regionProportionX
= xp
;
1862 m_regionProportionY
= yp
;
1865 void wxShapeRegion::SetFormatMode(int mode
)
1867 m_formatMode
= mode
;
1870 void wxShapeRegion::SetColour(const wxString
& col
)
1873 m_actualColourObject
= NULL
;
1876 wxColour
*wxShapeRegion::GetActualColourObject()
1878 if (!m_actualColourObject
)
1879 m_actualColourObject
= wxTheColourDatabase
->FindColour(GetColour());
1880 if (!m_actualColourObject
)
1881 m_actualColourObject
= wxBLACK
;
1882 return m_actualColourObject
;
1885 void wxShapeRegion::SetPenColour(const wxString
& col
)
1888 m_actualPenObject
= NULL
;
1891 // Returns NULL if the pen is invisible
1892 // (different to pen being transparent; indicates that
1893 // region boundary should not be drawn.)
1894 wxPen
*wxShapeRegion::GetActualPen()
1896 if (m_actualPenObject
)
1897 return m_actualPenObject
;
1899 if (!m_penColour
) return NULL
;
1900 if (m_penColour
== "Invisible")
1902 m_actualPenObject
= wxThePenList
->FindOrCreatePen(m_penColour
, 1, m_penStyle
);
1903 return m_actualPenObject
;