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
)
68 m_originalPoints
= new wxList
;
69 m_points
= new wxList
;
73 m_originalPoints
= the_points
;
75 // Duplicate the list of points
76 m_points
= new wxList
;
78 wxObjectList::compatibility_iterator node
= the_points
->GetFirst();
81 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
82 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
83 m_points
->Append((wxObject
*) new_point
);
84 node
= node
->GetNext();
86 CalculateBoundingBox();
87 m_originalWidth
= m_boundWidth
;
88 m_originalHeight
= m_boundHeight
;
89 SetDefaultRegionSize();
93 wxPolygonShape::~wxPolygonShape()
98 void wxPolygonShape::ClearPoints()
102 wxObjectList::compatibility_iterator node
= m_points
->GetFirst();
105 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
107 m_points
->Erase(node
);
108 node
= m_points
->GetFirst();
113 if (m_originalPoints
)
115 wxObjectList::compatibility_iterator node
= m_originalPoints
->GetFirst();
118 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
120 m_originalPoints
->Erase(node
);
121 node
= m_originalPoints
->GetFirst();
123 delete m_originalPoints
;
124 m_originalPoints
= NULL
;
129 // Width and height. Centre of object is centre of box.
130 void wxPolygonShape::GetBoundingBoxMin(double *width
, double *height
)
132 *width
= m_boundWidth
;
133 *height
= m_boundHeight
;
136 void wxPolygonShape::CalculateBoundingBox()
138 // Calculate bounding box at construction (and presumably resize) time
140 double right
= -10000;
142 double bottom
= -10000;
144 wxObjectList::compatibility_iterator node
= m_points
->GetFirst();
147 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
148 if (point
->x
< left
) left
= point
->x
;
149 if (point
->x
> right
) right
= point
->x
;
151 if (point
->y
< top
) top
= point
->y
;
152 if (point
->y
> bottom
) bottom
= point
->y
;
154 node
= node
->GetNext();
156 m_boundWidth
= right
- left
;
157 m_boundHeight
= bottom
- top
;
160 // Recalculates the centre of the polygon, and
161 // readjusts the point offsets accordingly.
162 // Necessary since the centre of the polygon
163 // is expected to be the real centre of the bounding
165 void wxPolygonShape::CalculatePolygonCentre()
168 double right
= -10000;
170 double bottom
= -10000;
172 wxObjectList::compatibility_iterator node
= m_points
->GetFirst();
175 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
176 if (point
->x
< left
) left
= point
->x
;
177 if (point
->x
> right
) right
= point
->x
;
179 if (point
->y
< top
) top
= point
->y
;
180 if (point
->y
> bottom
) bottom
= point
->y
;
182 node
= node
->GetNext();
184 double bwidth
= right
- left
;
185 double bheight
= bottom
- top
;
187 double newCentreX
= (double)(left
+ (bwidth
/2.0));
188 double newCentreY
= (double)(top
+ (bheight
/2.0));
190 node
= m_points
->GetFirst();
193 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
194 point
->x
-= newCentreX
;
195 point
->y
-= newCentreY
;
196 node
= node
->GetNext();
198 m_xpos
+= newCentreX
;
199 m_ypos
+= newCentreY
;
202 bool PolylineHitTest(double n
, double xvec
[], double yvec
[],
203 double x1
, double y1
, double x2
, double y2
)
207 double lastx
= xvec
[0];
208 double lasty
= yvec
[0];
210 double min_ratio
= 1.0;
214 for (i
= 1; i
< n
; i
++)
216 oglCheckLineIntersection(x1
, y1
, x2
, y2
, lastx
, lasty
, xvec
[i
], yvec
[i
],
217 &line_ratio
, &other_ratio
);
218 if (line_ratio
!= 1.0)
223 if (line_ratio
< min_ratio
)
224 min_ratio
= line_ratio
;
227 // Do last (implicit) line if last and first doubles are not identical
228 if (!(xvec
[0] == lastx
&& yvec
[0] == lasty
))
230 oglCheckLineIntersection(x1
, y1
, x2
, y2
, lastx
, lasty
, xvec
[0], yvec
[0],
231 &line_ratio
, &other_ratio
);
232 if (line_ratio
!= 1.0)
239 bool wxPolygonShape::HitTest(double x
, double y
, int *attachment
, double *distance
)
241 // Imagine four lines radiating from this point. If all of these lines hit the polygon,
242 // we're inside it, otherwise we're not. Obviously we'd need more radiating lines
243 // to be sure of correct results for very strange (concave) shapes.
244 double endPointsX
[4];
245 double endPointsY
[4];
248 endPointsY
[0] = (double)(y
- 1000.0);
250 endPointsX
[1] = (double)(x
+ 1000.0);
254 endPointsY
[2] = (double)(y
+ 1000.0);
256 endPointsX
[3] = (double)(x
- 1000.0);
259 // Store polygon points in an array
260 int np
= m_points
->GetCount();
261 double *xpoints
= new double[np
];
262 double *ypoints
= new double[np
];
263 wxObjectList::compatibility_iterator node
= m_points
->GetFirst();
267 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
268 xpoints
[i
] = point
->x
+ m_xpos
;
269 ypoints
[i
] = point
->y
+ m_ypos
;
270 node
= node
->GetNext();
274 // We assume it's inside the polygon UNLESS one or more
275 // lines don't hit the outline.
276 bool isContained
= true;
279 for (i
= 0; i
< noPoints
; i
++)
281 if (!PolylineHitTest(np
, xpoints
, ypoints
, x
, y
, endPointsX
[i
], endPointsY
[i
]))
286 ClipsErrorFunction("It's a hit!\n");
288 ClipsErrorFunction("No hit.\n");
296 int nearest_attachment
= 0;
298 // If a hit, check the attachment points within the object.
299 int n
= GetNumberOfAttachments();
300 double nearest
= 999999.0;
302 for (i
= 0; i
< n
; i
++)
305 if (GetAttachmentPositionEdge(i
, &xp
, &yp
))
307 double l
= (double)sqrt(((xp
- x
) * (xp
- x
)) +
308 ((yp
- y
) * (yp
- y
)));
312 nearest_attachment
= i
;
316 *attachment
= nearest_attachment
;
321 // Really need to be able to reset the shape! Otherwise, if the
322 // points ever go to zero, we've lost it, and can't resize.
323 void wxPolygonShape::SetSize(double new_width
, double new_height
, bool WXUNUSED(recursive
))
325 SetAttachmentSize(new_width
, new_height
);
327 // Multiply all points by proportion of new size to old size
328 double x_proportion
= (double)(fabs(new_width
/m_originalWidth
));
329 double y_proportion
= (double)(fabs(new_height
/m_originalHeight
));
331 wxObjectList::compatibility_iterator node
= m_points
->GetFirst();
332 wxObjectList::compatibility_iterator original_node
= m_originalPoints
->GetFirst();
333 while (node
&& original_node
)
335 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
336 wxRealPoint
*original_point
= (wxRealPoint
*)original_node
->GetData();
338 point
->x
= (original_point
->x
* x_proportion
);
339 point
->y
= (original_point
->y
* y_proportion
);
341 node
= node
->GetNext();
342 original_node
= original_node
->GetNext();
345 // CalculateBoundingBox();
346 m_boundWidth
= (double)fabs(new_width
);
347 m_boundHeight
= (double)fabs(new_height
);
348 SetDefaultRegionSize();
351 // Make the original points the same as the working points
352 void wxPolygonShape::UpdateOriginalPoints()
354 if (!m_originalPoints
) m_originalPoints
= new wxList
;
355 wxObjectList::compatibility_iterator original_node
= m_originalPoints
->GetFirst();
356 while (original_node
)
358 wxObjectList::compatibility_iterator next_node
= original_node
->GetNext();
359 wxRealPoint
*original_point
= (wxRealPoint
*)original_node
->GetData();
360 delete original_point
;
361 m_originalPoints
->Erase(original_node
);
363 original_node
= next_node
;
366 wxObjectList::compatibility_iterator node
= m_points
->GetFirst();
369 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
370 wxRealPoint
*original_point
= new wxRealPoint(point
->x
, point
->y
);
371 m_originalPoints
->Append((wxObject
*) original_point
);
373 node
= node
->GetNext();
375 CalculateBoundingBox();
376 m_originalWidth
= m_boundWidth
;
377 m_originalHeight
= m_boundHeight
;
380 void wxPolygonShape::AddPolygonPoint(int pos
)
382 wxObjectList::compatibility_iterator node
= m_points
->Item(pos
);
383 if (!node
) node
= m_points
->GetFirst();
384 wxRealPoint
*firstPoint
= (wxRealPoint
*)node
->GetData();
386 wxObjectList::compatibility_iterator node2
= m_points
->Item(pos
+ 1);
387 if (!node2
) node2
= m_points
->GetFirst();
388 wxRealPoint
*secondPoint
= (wxRealPoint
*)node2
->GetData();
390 double x
= (double)((secondPoint
->x
- firstPoint
->x
)/2.0 + firstPoint
->x
);
391 double y
= (double)((secondPoint
->y
- firstPoint
->y
)/2.0 + firstPoint
->y
);
392 wxRealPoint
*point
= new wxRealPoint(x
, y
);
394 if (pos
>= (int) (m_points
->GetCount() - 1))
395 m_points
->Append((wxObject
*) point
);
397 m_points
->Insert(node2
, (wxObject
*) point
);
399 UpdateOriginalPoints();
403 DeleteControlPoints();
408 void wxPolygonShape::DeletePolygonPoint(int pos
)
410 wxObjectList::compatibility_iterator node
= m_points
->Item(pos
);
413 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
415 m_points
->Erase(node
);
416 UpdateOriginalPoints();
419 DeleteControlPoints();
425 // Assume (x1, y1) is centre of box (most generally, line end at box)
426 bool wxPolygonShape::GetPerimeterPoint(double x1
, double y1
,
427 double x2
, double y2
,
428 double *x3
, double *y3
)
430 int n
= m_points
->GetCount();
432 // First check for situation where the line is vertical,
433 // and we would want to connect to a point on that vertical --
434 // oglFindEndForPolyline can't cope with this (the arrow
435 // gets drawn to the wrong place).
436 if ((m_attachmentMode
== ATTACHMENT_MODE_NONE
) && (x1
== x2
))
438 // Look for the point we'd be connecting to. This is
440 wxObjectList::compatibility_iterator node
= m_points
->GetFirst();
443 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
446 if ((y2
> y1
) && (point
->y
> 0.0))
448 *x3
= point
->x
+ m_xpos
;
449 *y3
= point
->y
+ m_ypos
;
452 else if ((y2
< y1
) && (point
->y
< 0.0))
454 *x3
= point
->x
+ m_xpos
;
455 *y3
= point
->y
+ m_ypos
;
459 node
= node
->GetNext();
463 double *xpoints
= new double[n
];
464 double *ypoints
= new double[n
];
466 wxObjectList::compatibility_iterator node
= m_points
->GetFirst();
470 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
471 xpoints
[i
] = point
->x
+ m_xpos
;
472 ypoints
[i
] = point
->y
+ m_ypos
;
473 node
= node
->GetNext();
477 oglFindEndForPolyline(n
, xpoints
, ypoints
,
478 x1
, y1
, x2
, y2
, x3
, y3
);
486 void wxPolygonShape::OnDraw(wxDC
& dc
)
488 int n
= m_points
->GetCount();
489 wxPoint
*intPoints
= new wxPoint
[n
];
491 for (i
= 0; i
< n
; i
++)
493 wxRealPoint
* point
= (wxRealPoint
*) m_points
->Item(i
)->GetData();
494 intPoints
[i
].x
= WXROUND(point
->x
);
495 intPoints
[i
].y
= WXROUND(point
->y
);
498 if (m_shadowMode
!= SHADOW_NONE
)
501 dc
.SetBrush(* m_shadowBrush
);
502 dc
.SetPen(* g_oglTransparentPen
);
504 dc
.DrawPolygon(n
, intPoints
, WXROUND(m_xpos
+ m_shadowOffsetX
), WXROUND(m_ypos
+ m_shadowOffsetY
));
509 if (m_pen
->GetWidth() == 0)
510 dc
.SetPen(* g_oglTransparentPen
);
515 dc
.SetBrush(* m_brush
);
516 dc
.DrawPolygon(n
, intPoints
, WXROUND(m_xpos
), WXROUND(m_ypos
));
521 void wxPolygonShape::OnDrawOutline(wxDC
& dc
, double x
, double y
, double w
, double h
)
523 dc
.SetBrush(* wxTRANSPARENT_BRUSH
);
524 // Multiply all points by proportion of new size to old size
525 double x_proportion
= (double)(fabs(w
/m_originalWidth
));
526 double y_proportion
= (double)(fabs(h
/m_originalHeight
));
528 int n
= m_originalPoints
->GetCount();
529 wxPoint
*intPoints
= new wxPoint
[n
];
531 for (i
= 0; i
< n
; i
++)
533 wxRealPoint
* point
= (wxRealPoint
*) m_originalPoints
->Item(i
)->GetData();
534 intPoints
[i
].x
= WXROUND(x_proportion
* point
->x
);
535 intPoints
[i
].y
= WXROUND(y_proportion
* point
->y
);
537 dc
.DrawPolygon(n
, intPoints
, WXROUND(x
), WXROUND(y
));
541 // Make as many control points as there are vertices.
542 void wxPolygonShape::MakeControlPoints()
544 wxObjectList::compatibility_iterator node
= m_points
->GetFirst();
547 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
548 wxPolygonControlPoint
*control
= new wxPolygonControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
,
549 point
, point
->x
, point
->y
);
550 m_canvas
->AddShape(control
);
551 m_controlPoints
.Append(control
);
552 node
= node
->GetNext();
556 void wxPolygonShape::ResetControlPoints()
558 wxObjectList::compatibility_iterator node
= m_points
->GetFirst();
559 wxObjectList::compatibility_iterator controlPointNode
= m_controlPoints
.GetFirst();
560 while (node
&& controlPointNode
)
562 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
563 wxPolygonControlPoint
*controlPoint
= (wxPolygonControlPoint
*)controlPointNode
->GetData();
565 controlPoint
->m_xoffset
= point
->x
;
566 controlPoint
->m_yoffset
= point
->y
;
567 controlPoint
->m_polygonVertex
= point
;
569 node
= node
->GetNext();
570 controlPointNode
= controlPointNode
->GetNext();
576 void wxPolygonShape::WriteAttributes(wxExpr
*clause
)
578 wxShape::WriteAttributes(clause
);
580 clause
->AddAttributeValue(wxT("x"), m_xpos
);
581 clause
->AddAttributeValue(wxT("y"), m_ypos
);
583 // Make a list of lists for the coordinates
584 wxExpr
*list
= new wxExpr(wxExprList
);
585 wxObjectList::compatibility_iterator node
= m_points
->GetFirst();
588 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
589 wxExpr
*point_list
= new wxExpr(wxExprList
);
590 wxExpr
*x_expr
= new wxExpr((double)point
->x
);
591 wxExpr
*y_expr
= new wxExpr((double)point
->y
);
593 point_list
->Append(x_expr
);
594 point_list
->Append(y_expr
);
595 list
->Append(point_list
);
597 node
= node
->GetNext();
599 clause
->AddAttributeValue(wxT("points"), list
);
601 // Save the original (unscaled) points
602 list
= new wxExpr(wxExprList
);
603 node
= m_originalPoints
->GetFirst();
606 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
607 wxExpr
*point_list
= new wxExpr(wxExprList
);
608 wxExpr
*x_expr
= new wxExpr((double) point
->x
);
609 wxExpr
*y_expr
= new wxExpr((double) point
->y
);
610 point_list
->Append(x_expr
);
611 point_list
->Append(y_expr
);
612 list
->Append(point_list
);
614 node
= node
->GetNext();
616 clause
->AddAttributeValue(wxT("m_originalPoints"), list
);
619 void wxPolygonShape::ReadAttributes(wxExpr
*clause
)
621 wxShape::ReadAttributes(clause
);
623 // Read a list of lists
624 m_points
= new wxList
;
625 m_originalPoints
= new wxList
;
627 wxExpr
*points_list
= NULL
;
628 clause
->AssignAttributeValue(wxT("points"), &points_list
);
630 // If no points_list, don't crash!! Assume a diamond instead.
631 double the_height
= 100.0;
632 double the_width
= 100.0;
635 wxRealPoint
*point
= new wxRealPoint(0.0, (-the_height
/2));
636 m_points
->Append((wxObject
*) point
);
638 point
= new wxRealPoint((the_width
/2), 0.0);
639 m_points
->Append((wxObject
*) point
);
641 point
= new wxRealPoint(0.0, (the_height
/2));
642 m_points
->Append((wxObject
*) point
);
644 point
= new wxRealPoint((-the_width
/2), 0.0);
645 m_points
->Append((wxObject
*) point
);
647 point
= new wxRealPoint(0.0, (-the_height
/2));
648 m_points
->Append((wxObject
*) point
);
652 wxExpr
*node
= points_list
->value
.first
;
656 wxExpr
*xexpr
= node
->value
.first
;
657 long x
= xexpr
->IntegerValue();
659 wxExpr
*yexpr
= xexpr
->next
;
660 long y
= yexpr
->IntegerValue();
662 wxRealPoint
*point
= new wxRealPoint((double)x
, (double)y
);
663 m_points
->Append((wxObject
*) point
);
670 clause
->AssignAttributeValue(wxT("m_originalPoints"), &points_list
);
672 // If no points_list, don't crash!! Assume a diamond instead.
675 wxRealPoint
*point
= new wxRealPoint(0.0, (-the_height
/2));
676 m_originalPoints
->Append((wxObject
*) point
);
678 point
= new wxRealPoint((the_width
/2), 0.0);
679 m_originalPoints
->Append((wxObject
*) point
);
681 point
= new wxRealPoint(0.0, (the_height
/2));
682 m_originalPoints
->Append((wxObject
*) point
);
684 point
= new wxRealPoint((-the_width
/2), 0.0);
685 m_originalPoints
->Append((wxObject
*) point
);
687 point
= new wxRealPoint(0.0, (-the_height
/2));
688 m_originalPoints
->Append((wxObject
*) point
);
690 m_originalWidth
= the_width
;
691 m_originalHeight
= the_height
;
695 wxExpr
*node
= points_list
->value
.first
;
698 double max_x
= -1000;
699 double max_y
= -1000;
702 wxExpr
*xexpr
= node
->value
.first
;
703 long x
= xexpr
->IntegerValue();
705 wxExpr
*yexpr
= xexpr
->next
;
706 long y
= yexpr
->IntegerValue();
708 wxRealPoint
*point
= new wxRealPoint((double)x
, (double)y
);
709 m_originalPoints
->Append((wxObject
*) point
);
722 m_originalWidth
= max_x
- min_x
;
723 m_originalHeight
= max_y
- min_y
;
726 CalculateBoundingBox();
730 void wxPolygonShape::Copy(wxShape
& copy
)
734 wxASSERT( copy
.IsKindOf(CLASSINFO(wxPolygonShape
)) );
736 wxPolygonShape
& polyCopy
= (wxPolygonShape
&) copy
;
738 polyCopy
.ClearPoints();
740 polyCopy
.m_points
= new wxList
;
741 polyCopy
.m_originalPoints
= new wxList
;
743 wxObjectList::compatibility_iterator node
= m_points
->GetFirst();
746 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
747 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
748 polyCopy
.m_points
->Append((wxObject
*) new_point
);
749 node
= node
->GetNext();
751 node
= m_originalPoints
->GetFirst();
754 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
755 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
756 polyCopy
.m_originalPoints
->Append((wxObject
*) new_point
);
757 node
= node
->GetNext();
759 polyCopy
.m_boundWidth
= m_boundWidth
;
760 polyCopy
.m_boundHeight
= m_boundHeight
;
761 polyCopy
.m_originalWidth
= m_originalWidth
;
762 polyCopy
.m_originalHeight
= m_originalHeight
;
765 int wxPolygonShape::GetNumberOfAttachments() const
767 int maxN
= (m_points
? (m_points
->GetCount() - 1) : 0);
768 wxObjectList::compatibility_iterator node
= m_attachmentPoints
.GetFirst();
771 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->GetData();
772 if (point
->m_id
> maxN
)
774 node
= node
->GetNext();
779 bool wxPolygonShape::GetAttachmentPosition(int attachment
, double *x
, double *y
,
780 int nth
, int no_arcs
, wxLineShape
*line
)
782 if ((m_attachmentMode
== ATTACHMENT_MODE_EDGE
) && m_points
&& attachment
< (int) m_points
->GetCount())
784 wxRealPoint
*point
= (wxRealPoint
*)m_points
->Item(attachment
)->GetData();
785 *x
= point
->x
+ m_xpos
;
786 *y
= point
->y
+ m_ypos
;
790 { return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
); }
793 bool wxPolygonShape::AttachmentIsValid(int attachment
) const
798 if ((attachment
>= 0) && (attachment
< (int) m_points
->GetCount()))
801 wxObjectList::compatibility_iterator node
= m_attachmentPoints
.GetFirst();
804 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->GetData();
805 if (point
->m_id
== attachment
)
807 node
= node
->GetNext();
812 // Rotate about the given axis by the given amount in radians
813 void wxPolygonShape::Rotate(double x
, double y
, double theta
)
815 double actualTheta
= theta
-m_rotation
;
817 // Rotate attachment points
818 double sinTheta
= (double)sin(actualTheta
);
819 double cosTheta
= (double)cos(actualTheta
);
820 wxObjectList::compatibility_iterator node
= m_attachmentPoints
.GetFirst();
823 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->GetData();
824 double x1
= point
->m_x
;
825 double y1
= point
->m_y
;
826 point
->m_x
= x1
*cosTheta
- y1
*sinTheta
+ x
*(1.0 - cosTheta
) + y
*sinTheta
;
827 point
->m_y
= x1
*sinTheta
+ y1
*cosTheta
+ y
*(1.0 - cosTheta
) + x
*sinTheta
;
828 node
= node
->GetNext();
831 node
= m_points
->GetFirst();
834 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
835 double x1
= point
->x
;
836 double y1
= point
->y
;
837 point
->x
= x1
*cosTheta
- y1
*sinTheta
+ x
*(1.0 - cosTheta
) + y
*sinTheta
;
838 point
->y
= x1
*sinTheta
+ y1
*cosTheta
+ y
*(1.0 - cosTheta
) + x
*sinTheta
;
839 node
= node
->GetNext();
841 node
= m_originalPoints
->GetFirst();
844 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
845 double x1
= point
->x
;
846 double y1
= point
->y
;
847 point
->x
= x1
*cosTheta
- y1
*sinTheta
+ x
*(1.0 - cosTheta
) + y
*sinTheta
;
848 point
->y
= x1
*sinTheta
+ y1
*cosTheta
+ y
*(1.0 - cosTheta
) + x
*sinTheta
;
849 node
= node
->GetNext();
854 CalculatePolygonCentre();
855 CalculateBoundingBox();
856 ResetControlPoints();
861 IMPLEMENT_DYNAMIC_CLASS(wxRectangleShape
, wxShape
)
863 wxRectangleShape::wxRectangleShape(double w
, double h
)
865 m_width
= w
; m_height
= h
; m_cornerRadius
= 0.0;
866 SetDefaultRegionSize();
869 void wxRectangleShape::OnDraw(wxDC
& dc
)
871 double x1
= (double)(m_xpos
- m_width
/2.0);
872 double y1
= (double)(m_ypos
- m_height
/2.0);
874 if (m_shadowMode
!= SHADOW_NONE
)
877 dc
.SetBrush(* m_shadowBrush
);
878 dc
.SetPen(* g_oglTransparentPen
);
880 if (m_cornerRadius
!= 0.0)
881 dc
.DrawRoundedRectangle(WXROUND(x1
+ m_shadowOffsetX
), WXROUND(y1
+ m_shadowOffsetY
),
882 WXROUND(m_width
), WXROUND(m_height
), m_cornerRadius
);
884 dc
.DrawRectangle(WXROUND(x1
+ m_shadowOffsetX
), WXROUND(y1
+ m_shadowOffsetY
), WXROUND(m_width
), WXROUND(m_height
));
889 if (m_pen
->GetWidth() == 0)
890 dc
.SetPen(* g_oglTransparentPen
);
895 dc
.SetBrush(* m_brush
);
897 if (m_cornerRadius
!= 0.0)
898 dc
.DrawRoundedRectangle(WXROUND(x1
), WXROUND(y1
), WXROUND(m_width
), WXROUND(m_height
), m_cornerRadius
);
900 dc
.DrawRectangle(WXROUND(x1
), WXROUND(y1
), WXROUND(m_width
), WXROUND(m_height
));
903 void wxRectangleShape::GetBoundingBoxMin(double *the_width
, double *the_height
)
905 *the_width
= m_width
;
906 *the_height
= m_height
;
909 void wxRectangleShape::SetSize(double x
, double y
, bool WXUNUSED(recursive
))
911 SetAttachmentSize(x
, y
);
912 m_width
= (double)wxMax(x
, 1.0);
913 m_height
= (double)wxMax(y
, 1.0);
914 SetDefaultRegionSize();
917 void wxRectangleShape::SetCornerRadius(double rad
)
919 m_cornerRadius
= rad
;
922 // Assume (x1, y1) is centre of box (most generally, line end at box)
923 bool wxRectangleShape::GetPerimeterPoint(double WXUNUSED(x1
), double WXUNUSED(y1
),
924 double x2
, double y2
,
925 double *x3
, double *y3
)
927 double bound_x
, bound_y
;
928 GetBoundingBoxMax(&bound_x
, &bound_y
);
929 oglFindEndForBox(bound_x
, bound_y
, m_xpos
, m_ypos
, x2
, y2
, x3
, y3
);
935 void wxRectangleShape::WriteAttributes(wxExpr
*clause
)
937 wxShape::WriteAttributes(clause
);
938 clause
->AddAttributeValue(wxT("x"), m_xpos
);
939 clause
->AddAttributeValue(wxT("y"), m_ypos
);
941 clause
->AddAttributeValue(wxT("width"), m_width
);
942 clause
->AddAttributeValue(wxT("height"), m_height
);
943 if (m_cornerRadius
!= 0.0)
944 clause
->AddAttributeValue(wxT("corner"), m_cornerRadius
);
947 void wxRectangleShape::ReadAttributes(wxExpr
*clause
)
949 wxShape::ReadAttributes(clause
);
950 clause
->AssignAttributeValue(wxT("width"), &m_width
);
951 clause
->AssignAttributeValue(wxT("height"), &m_height
);
952 clause
->AssignAttributeValue(wxT("corner"), &m_cornerRadius
);
954 // In case we're reading an old file, set the region's size
955 if (m_regions
.GetCount() == 1)
957 wxShapeRegion
*region
= (wxShapeRegion
*)m_regions
.GetFirst()->GetData();
958 region
->SetSize(m_width
, m_height
);
963 void wxRectangleShape::Copy(wxShape
& copy
)
967 wxASSERT( copy
.IsKindOf(CLASSINFO(wxRectangleShape
)) );
969 wxRectangleShape
& rectCopy
= (wxRectangleShape
&) copy
;
970 rectCopy
.m_width
= m_width
;
971 rectCopy
.m_height
= m_height
;
972 rectCopy
.m_cornerRadius
= m_cornerRadius
;
975 int wxRectangleShape::GetNumberOfAttachments() const
977 return wxShape::GetNumberOfAttachments();
981 // There are 4 attachment points on a rectangle - 0 = top, 1 = right, 2 = bottom,
983 bool wxRectangleShape::GetAttachmentPosition(int attachment
, double *x
, double *y
,
984 int nth
, int no_arcs
, wxLineShape
*line
)
986 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
989 // Text object (no box)
991 IMPLEMENT_DYNAMIC_CLASS(wxTextShape
, wxRectangleShape
)
993 wxTextShape::wxTextShape(double width
, double height
):
994 wxRectangleShape(width
, height
)
998 void wxTextShape::OnDraw(wxDC
& WXUNUSED(dc
))
1002 void wxTextShape::Copy(wxShape
& copy
)
1004 wxRectangleShape::Copy(copy
);
1008 void wxTextShape::WriteAttributes(wxExpr
*clause
)
1010 wxRectangleShape::WriteAttributes(clause
);
1016 IMPLEMENT_DYNAMIC_CLASS(wxEllipseShape
, wxShape
)
1018 wxEllipseShape::wxEllipseShape(double w
, double h
)
1020 m_width
= w
; m_height
= h
;
1021 SetDefaultRegionSize();
1024 void wxEllipseShape::GetBoundingBoxMin(double *w
, double *h
)
1026 *w
= m_width
; *h
= m_height
;
1029 bool wxEllipseShape::GetPerimeterPoint(double x1
, double y1
,
1030 double x2
, double y2
,
1031 double *x3
, double *y3
)
1033 double bound_x
, bound_y
;
1034 GetBoundingBoxMax(&bound_x
, &bound_y
);
1036 // oglFindEndForBox(bound_x, bound_y, m_xpos, m_ypos, x2, y2, x3, y3);
1037 oglDrawArcToEllipse(m_xpos
, m_ypos
, bound_x
, bound_y
, x2
, y2
, x1
, y1
, x3
, y3
);
1042 void wxEllipseShape::OnDraw(wxDC
& dc
)
1044 if (m_shadowMode
!= SHADOW_NONE
)
1047 dc
.SetBrush(* m_shadowBrush
);
1048 dc
.SetPen(* g_oglTransparentPen
);
1049 dc
.DrawEllipse((long) ((m_xpos
- GetWidth()/2) + m_shadowOffsetX
),
1050 (long) ((m_ypos
- GetHeight()/2) + m_shadowOffsetY
),
1051 (long) GetWidth(), (long) GetHeight());
1056 if (m_pen
->GetWidth() == 0)
1057 dc
.SetPen(* g_oglTransparentPen
);
1062 dc
.SetBrush(* m_brush
);
1063 dc
.DrawEllipse((long) (m_xpos
- GetWidth()/2), (long) (m_ypos
- GetHeight()/2), (long) GetWidth(), (long) GetHeight());
1066 void wxEllipseShape::SetSize(double x
, double y
, bool WXUNUSED(recursive
))
1068 SetAttachmentSize(x
, y
);
1071 SetDefaultRegionSize();
1075 void wxEllipseShape::WriteAttributes(wxExpr
*clause
)
1077 wxShape::WriteAttributes(clause
);
1078 clause
->AddAttributeValue(wxT("x"), m_xpos
);
1079 clause
->AddAttributeValue(wxT("y"), m_ypos
);
1081 clause
->AddAttributeValue(wxT("width"), m_width
);
1082 clause
->AddAttributeValue(wxT("height"), m_height
);
1085 void wxEllipseShape::ReadAttributes(wxExpr
*clause
)
1087 wxShape::ReadAttributes(clause
);
1088 clause
->AssignAttributeValue(wxT("width"), &m_width
);
1089 clause
->AssignAttributeValue(wxT("height"), &m_height
);
1091 // In case we're reading an old file, set the region's size
1092 if (m_regions
.GetCount() == 1)
1094 wxShapeRegion
*region
= (wxShapeRegion
*)m_regions
.GetFirst()->GetData();
1095 region
->SetSize(m_width
, m_height
);
1100 void wxEllipseShape::Copy(wxShape
& copy
)
1102 wxShape::Copy(copy
);
1104 wxASSERT( copy
.IsKindOf(CLASSINFO(wxEllipseShape
)) );
1106 wxEllipseShape
& ellipseCopy
= (wxEllipseShape
&) copy
;
1108 ellipseCopy
.m_width
= m_width
;
1109 ellipseCopy
.m_height
= m_height
;
1112 int wxEllipseShape::GetNumberOfAttachments() const
1114 return wxShape::GetNumberOfAttachments();
1117 // There are 4 attachment points on an ellipse - 0 = top, 1 = right, 2 = bottom,
1119 bool wxEllipseShape::GetAttachmentPosition(int attachment
, double *x
, double *y
,
1120 int nth
, int no_arcs
, wxLineShape
*line
)
1122 if (m_attachmentMode
== ATTACHMENT_MODE_BRANCHING
)
1123 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
1125 if (m_attachmentMode
!= ATTACHMENT_MODE_NONE
)
1127 double top
= (double)(m_ypos
+ m_height
/2.0);
1128 double bottom
= (double)(m_ypos
- m_height
/2.0);
1129 double left
= (double)(m_xpos
- m_width
/2.0);
1130 double right
= (double)(m_xpos
+ m_width
/2.0);
1132 int physicalAttachment
= LogicalToPhysicalAttachment(attachment
);
1134 switch (physicalAttachment
)
1138 if (m_spaceAttachments
)
1139 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
1142 // We now have the point on the bounding box: but get the point on the ellipse
1143 // by imagining a vertical line from (*x, m_ypos - m_height- 500) to (*x, m_ypos) intersecting
1145 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, *x
, (double)(m_ypos
-m_height
-500), *x
, m_ypos
, x
, y
);
1151 if (m_spaceAttachments
)
1152 *y
= bottom
+ (nth
+ 1)*m_height
/(no_arcs
+ 1);
1154 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, (double)(m_xpos
+m_width
+500), *y
, m_xpos
, *y
, x
, y
);
1159 if (m_spaceAttachments
)
1160 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
1163 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, *x
, (double)(m_ypos
+m_height
+500), *x
, m_ypos
, x
, y
);
1169 if (m_spaceAttachments
)
1170 *y
= bottom
+ (nth
+ 1)*m_height
/(no_arcs
+ 1);
1172 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, (double)(m_xpos
-m_width
-500), *y
, m_xpos
, *y
, x
, y
);
1177 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
1183 { *x
= m_xpos
; *y
= m_ypos
; return true; }
1188 IMPLEMENT_DYNAMIC_CLASS(wxCircleShape
, wxEllipseShape
)
1190 wxCircleShape::wxCircleShape(double diameter
):wxEllipseShape(diameter
, diameter
)
1192 SetMaintainAspectRatio(true);
1195 void wxCircleShape::Copy(wxShape
& copy
)
1197 wxEllipseShape::Copy(copy
);
1200 bool wxCircleShape::GetPerimeterPoint(double WXUNUSED(x1
), double WXUNUSED(y1
),
1201 double x2
, double y2
,
1202 double *x3
, double *y3
)
1204 oglFindEndForCircle(m_width
/2,
1205 m_xpos
, m_ypos
, // Centre of circle
1206 x2
, y2
, // Other end of line
1214 double wxControlPoint::sm_controlPointDragStartX
= 0.0;
1215 double wxControlPoint::sm_controlPointDragStartY
= 0.0;
1216 double wxControlPoint::sm_controlPointDragStartWidth
= 0.0;
1217 double wxControlPoint::sm_controlPointDragStartHeight
= 0.0;
1218 double wxControlPoint::sm_controlPointDragEndWidth
= 0.0;
1219 double wxControlPoint::sm_controlPointDragEndHeight
= 0.0;
1220 double wxControlPoint::sm_controlPointDragPosX
= 0.0;
1221 double wxControlPoint::sm_controlPointDragPosY
= 0.0;
1223 IMPLEMENT_DYNAMIC_CLASS(wxControlPoint
, wxRectangleShape
)
1225 wxControlPoint::wxControlPoint(wxShapeCanvas
*theCanvas
, wxShape
*object
, double size
, double the_xoffset
, double the_yoffset
, int the_type
):wxRectangleShape(size
, size
)
1227 m_canvas
= theCanvas
;
1229 m_xoffset
= the_xoffset
;
1230 m_yoffset
= the_yoffset
;
1232 SetPen(g_oglBlackForegroundPen
);
1233 SetBrush(wxBLACK_BRUSH
);
1236 m_eraseObject
= true;
1239 wxControlPoint::~wxControlPoint()
1243 // Don't even attempt to draw any text - waste of time!
1244 void wxControlPoint::OnDrawContents(wxDC
& WXUNUSED(dc
))
1248 void wxControlPoint::OnDraw(wxDC
& dc
)
1250 m_xpos
= m_shape
->GetX() + m_xoffset
;
1251 m_ypos
= m_shape
->GetY() + m_yoffset
;
1252 wxRectangleShape::OnDraw(dc
);
1255 void wxControlPoint::OnErase(wxDC
& dc
)
1257 wxRectangleShape::OnErase(dc
);
1260 // Implement resizing of canvas object
1261 void wxControlPoint::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
1263 m_shape
->GetEventHandler()->OnSizingDragLeft(this, draw
, x
, y
, keys
, attachment
);
1266 void wxControlPoint::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
1268 m_shape
->GetEventHandler()->OnSizingBeginDragLeft(this, x
, y
, keys
, attachment
);
1271 void wxControlPoint::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
1273 m_shape
->GetEventHandler()->OnSizingEndDragLeft(this, x
, y
, keys
, attachment
);
1276 int wxControlPoint::GetNumberOfAttachments() const
1281 bool wxControlPoint::GetAttachmentPosition(int WXUNUSED(attachment
), double *x
, double *y
,
1282 int WXUNUSED(nth
), int WXUNUSED(no_arcs
), wxLineShape
*WXUNUSED(line
))
1284 *x
= m_xpos
; *y
= m_ypos
;
1288 // Control points ('handles') redirect control to the actual shape, to make it easier
1289 // to override sizing behaviour.
1290 void wxShape::OnSizingDragLeft(wxControlPoint
* pt
, bool WXUNUSED(draw
), double x
, double y
, int keys
, int WXUNUSED(attachment
))
1294 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1296 wxClientDC
dc(GetCanvas());
1297 GetCanvas()->PrepareDC(dc
);
1299 dc
.SetLogicalFunction(OGLRBLF
);
1301 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1302 dc
.SetPen(dottedPen
);
1303 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1305 if (this->GetCentreResize())
1307 // Maintain the same centre point.
1308 double new_width
= (double)(2.0*fabs(x
- this->GetX()));
1309 double new_height
= (double)(2.0*fabs(y
- this->GetY()));
1311 // Constrain sizing according to what control point you're dragging
1312 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1314 if (GetMaintainAspectRatio())
1316 new_height
= bound_y
*(new_width
/bound_x
);
1319 new_height
= bound_y
;
1321 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1323 if (GetMaintainAspectRatio())
1325 new_width
= bound_x
*(new_height
/bound_y
);
1328 new_width
= bound_x
;
1330 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& (keys
& KEY_SHIFT
))
1331 new_height
= bound_y
*(new_width
/bound_x
);
1333 if (this->GetFixedWidth())
1334 new_width
= bound_x
;
1336 if (this->GetFixedHeight())
1337 new_height
= bound_y
;
1339 pt
->sm_controlPointDragEndWidth
= new_width
;
1340 pt
->sm_controlPointDragEndHeight
= new_height
;
1342 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1343 new_width
, new_height
);
1347 // Don't maintain the same centre point!
1348 double newX1
= wxMin(pt
->sm_controlPointDragStartX
, x
);
1349 double newY1
= wxMin(pt
->sm_controlPointDragStartY
, y
);
1350 double newX2
= wxMax(pt
->sm_controlPointDragStartX
, x
);
1351 double newY2
= wxMax(pt
->sm_controlPointDragStartY
, y
);
1352 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1354 newY1
= pt
->sm_controlPointDragStartY
;
1355 newY2
= newY1
+ pt
->sm_controlPointDragStartHeight
;
1357 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1359 newX1
= pt
->sm_controlPointDragStartX
;
1360 newX2
= newX1
+ pt
->sm_controlPointDragStartWidth
;
1362 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& ((keys
& KEY_SHIFT
) || GetMaintainAspectRatio()))
1364 double newH
= (double)((newX2
- newX1
)*(pt
->sm_controlPointDragStartHeight
/pt
->sm_controlPointDragStartWidth
));
1365 if (GetY() > pt
->sm_controlPointDragStartY
)
1366 newY2
= (double)(newY1
+ newH
);
1368 newY1
= (double)(newY2
- newH
);
1370 double newWidth
= (double)(newX2
- newX1
);
1371 double newHeight
= (double)(newY2
- newY1
);
1373 if (pt
->m_type
== CONTROL_POINT_VERTICAL
&& GetMaintainAspectRatio())
1375 newWidth
= bound_x
* (newHeight
/bound_y
) ;
1378 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
&& GetMaintainAspectRatio())
1380 newHeight
= bound_y
* (newWidth
/bound_x
) ;
1383 pt
->sm_controlPointDragPosX
= (double)(newX1
+ (newWidth
/2.0));
1384 pt
->sm_controlPointDragPosY
= (double)(newY1
+ (newHeight
/2.0));
1385 if (this->GetFixedWidth())
1388 if (this->GetFixedHeight())
1389 newHeight
= bound_y
;
1391 pt
->sm_controlPointDragEndWidth
= newWidth
;
1392 pt
->sm_controlPointDragEndHeight
= newHeight
;
1393 this->GetEventHandler()->OnDrawOutline(dc
, pt
->sm_controlPointDragPosX
, pt
->sm_controlPointDragPosY
, newWidth
, newHeight
);
1397 void wxShape::OnSizingBeginDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int WXUNUSED(attachment
))
1399 m_canvas
->CaptureMouse();
1401 wxClientDC
dc(GetCanvas());
1402 GetCanvas()->PrepareDC(dc
);
1404 if (pt->m_eraseObject)
1408 dc
.SetLogicalFunction(OGLRBLF
);
1412 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1413 this->GetEventHandler()->OnBeginSize(bound_x
, bound_y
);
1415 // Choose the 'opposite corner' of the object as the stationary
1416 // point in case this is non-centring resizing.
1417 if (pt
->GetX() < this->GetX())
1418 pt
->sm_controlPointDragStartX
= (double)(this->GetX() + (bound_x
/2.0));
1420 pt
->sm_controlPointDragStartX
= (double)(this->GetX() - (bound_x
/2.0));
1422 if (pt
->GetY() < this->GetY())
1423 pt
->sm_controlPointDragStartY
= (double)(this->GetY() + (bound_y
/2.0));
1425 pt
->sm_controlPointDragStartY
= (double)(this->GetY() - (bound_y
/2.0));
1427 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1428 pt
->sm_controlPointDragStartY
= (double)(this->GetY() - (bound_y
/2.0));
1429 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1430 pt
->sm_controlPointDragStartX
= (double)(this->GetX() - (bound_x
/2.0));
1432 // We may require the old width and height.
1433 pt
->sm_controlPointDragStartWidth
= bound_x
;
1434 pt
->sm_controlPointDragStartHeight
= bound_y
;
1436 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1437 dc
.SetPen(dottedPen
);
1438 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1440 if (this->GetCentreResize())
1442 double new_width
= (double)(2.0*fabs(x
- this->GetX()));
1443 double new_height
= (double)(2.0*fabs(y
- this->GetY()));
1445 // Constrain sizing according to what control point you're dragging
1446 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1448 if (GetMaintainAspectRatio())
1450 new_height
= bound_y
*(new_width
/bound_x
);
1453 new_height
= bound_y
;
1455 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1457 if (GetMaintainAspectRatio())
1459 new_width
= bound_x
*(new_height
/bound_y
);
1462 new_width
= bound_x
;
1464 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& (keys
& KEY_SHIFT
))
1465 new_height
= bound_y
*(new_width
/bound_x
);
1467 if (this->GetFixedWidth())
1468 new_width
= bound_x
;
1470 if (this->GetFixedHeight())
1471 new_height
= bound_y
;
1473 pt
->sm_controlPointDragEndWidth
= new_width
;
1474 pt
->sm_controlPointDragEndHeight
= new_height
;
1475 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1476 new_width
, new_height
);
1480 // Don't maintain the same centre point!
1481 double newX1
= wxMin(pt
->sm_controlPointDragStartX
, x
);
1482 double newY1
= wxMin(pt
->sm_controlPointDragStartY
, y
);
1483 double newX2
= wxMax(pt
->sm_controlPointDragStartX
, x
);
1484 double newY2
= wxMax(pt
->sm_controlPointDragStartY
, y
);
1485 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1487 newY1
= pt
->sm_controlPointDragStartY
;
1488 newY2
= newY1
+ pt
->sm_controlPointDragStartHeight
;
1490 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1492 newX1
= pt
->sm_controlPointDragStartX
;
1493 newX2
= newX1
+ pt
->sm_controlPointDragStartWidth
;
1495 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& ((keys
& KEY_SHIFT
) || GetMaintainAspectRatio()))
1497 double newH
= (double)((newX2
- newX1
)*(pt
->sm_controlPointDragStartHeight
/pt
->sm_controlPointDragStartWidth
));
1498 if (pt
->GetY() > pt
->sm_controlPointDragStartY
)
1499 newY2
= (double)(newY1
+ newH
);
1501 newY1
= (double)(newY2
- newH
);
1503 double newWidth
= (double)(newX2
- newX1
);
1504 double newHeight
= (double)(newY2
- newY1
);
1506 if (pt
->m_type
== CONTROL_POINT_VERTICAL
&& GetMaintainAspectRatio())
1508 newWidth
= bound_x
* (newHeight
/bound_y
) ;
1511 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
&& GetMaintainAspectRatio())
1513 newHeight
= bound_y
* (newWidth
/bound_x
) ;
1516 pt
->sm_controlPointDragPosX
= (double)(newX1
+ (newWidth
/2.0));
1517 pt
->sm_controlPointDragPosY
= (double)(newY1
+ (newHeight
/2.0));
1518 if (this->GetFixedWidth())
1521 if (this->GetFixedHeight())
1522 newHeight
= bound_y
;
1524 pt
->sm_controlPointDragEndWidth
= newWidth
;
1525 pt
->sm_controlPointDragEndHeight
= newHeight
;
1526 this->GetEventHandler()->OnDrawOutline(dc
, pt
->sm_controlPointDragPosX
, pt
->sm_controlPointDragPosY
, newWidth
, newHeight
);
1530 void wxShape::OnSizingEndDragLeft(wxControlPoint
* pt
, double WXUNUSED(x
), double WXUNUSED(y
), int WXUNUSED(keys
), int WXUNUSED(attachment
))
1532 wxClientDC
dc(GetCanvas());
1533 GetCanvas()->PrepareDC(dc
);
1535 m_canvas
->ReleaseMouse();
1536 dc
.SetLogicalFunction(wxCOPY
);
1538 this->ResetControlPoints();
1542 if (!pt->m_eraseObject)
1546 this->SetSize(pt
->sm_controlPointDragEndWidth
, pt
->sm_controlPointDragEndHeight
);
1548 // The next operation could destroy this control point (it does for label objects,
1549 // via formatting the text), so save all values we're going to use, or
1550 // we'll be accessing garbage.
1551 wxShape
*theObject
= this;
1552 wxShapeCanvas
*theCanvas
= m_canvas
;
1553 bool eraseIt
= pt
->m_eraseObject
;
1555 if (theObject
->GetCentreResize())
1556 theObject
->Move(dc
, theObject
->GetX(), theObject
->GetY());
1558 theObject
->Move(dc
, pt
->sm_controlPointDragPosX
, pt
->sm_controlPointDragPosY
);
1562 theObject->Show(true);
1565 // Recursively redraw links if we have a composite.
1566 if (theObject
->GetChildren().GetCount() > 0)
1567 theObject
->DrawLinks(dc
, -1, true);
1569 double width
, height
;
1570 theObject
->GetBoundingBoxMax(&width
, &height
);
1571 theObject
->GetEventHandler()->OnEndSize(width
, height
);
1573 if (!theCanvas
->GetQuickEditMode() && eraseIt
) theCanvas
->Redraw(dc
);
1578 // Polygon control points
1580 IMPLEMENT_DYNAMIC_CLASS(wxPolygonControlPoint
, wxControlPoint
)
1582 wxPolygonControlPoint::wxPolygonControlPoint(wxShapeCanvas
*theCanvas
, wxShape
*object
, double size
,
1583 wxRealPoint
*vertex
, double the_xoffset
, double the_yoffset
):
1584 wxControlPoint(theCanvas
, object
, size
, the_xoffset
, the_yoffset
, 0)
1586 m_polygonVertex
= vertex
;
1587 m_originalDistance
= 0.0;
1590 wxPolygonControlPoint::~wxPolygonControlPoint()
1594 // Calculate what new size would be, at end of resize
1595 void wxPolygonControlPoint::CalculateNewSize(double x
, double y
)
1599 GetShape()->GetBoundingBoxMin(&bound_x
, &bound_y
);
1601 double dist
= (double)sqrt((x
- m_shape
->GetX())*(x
- m_shape
->GetX()) +
1602 (y
- m_shape
->GetY())*(y
- m_shape
->GetY()));
1604 m_newSize
.x
= (double)(dist
/this->m_originalDistance
)*this->m_originalSize
.x
;
1605 m_newSize
.y
= (double)(dist
/this->m_originalDistance
)*this->m_originalSize
.y
;
1609 // Implement resizing polygon or moving the vertex.
1610 void wxPolygonControlPoint::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
1612 m_shape
->GetEventHandler()->OnSizingDragLeft(this, draw
, x
, y
, keys
, attachment
);
1615 void wxPolygonControlPoint::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
1617 m_shape
->GetEventHandler()->OnSizingBeginDragLeft(this, x
, y
, keys
, attachment
);
1620 void wxPolygonControlPoint::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
1622 m_shape
->GetEventHandler()->OnSizingEndDragLeft(this, x
, y
, keys
, attachment
);
1625 // Control points ('handles') redirect control to the actual shape, to make it easier
1626 // to override sizing behaviour.
1627 void wxPolygonShape::OnSizingDragLeft(wxControlPoint
* pt
, bool WXUNUSED(draw
), double x
, double y
, int WXUNUSED(keys
), int WXUNUSED(attachment
))
1629 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
1631 wxClientDC
dc(GetCanvas());
1632 GetCanvas()->PrepareDC(dc
);
1634 dc
.SetLogicalFunction(OGLRBLF
);
1636 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1637 dc
.SetPen(dottedPen
);
1638 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1640 #if 0 // keys & KEY_CTRL)
1642 // TODO: mend this code. Currently we rely on altering the
1643 // actual points, but we should assume we're not, as per
1644 // the normal sizing case.
1645 m_canvas
->Snap(&x
, &y
);
1648 ppt
->m_polygonVertex
->x
= x
- this->GetX();
1649 ppt
->m_polygonVertex
->y
= y
- this->GetY();
1652 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1653 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1657 ppt
->CalculateNewSize(x
, y
);
1661 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1662 ppt
->GetNewSize().x
, ppt
->GetNewSize().y
);
1665 void wxPolygonShape::OnSizingBeginDragLeft(wxControlPoint
* pt
, double x
, double y
, int WXUNUSED(keys
), int WXUNUSED(attachment
))
1667 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
1669 wxClientDC
dc(GetCanvas());
1670 GetCanvas()->PrepareDC(dc
);
1674 dc
.SetLogicalFunction(OGLRBLF
);
1678 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1680 double dist
= (double)sqrt((x
- this->GetX())*(x
- this->GetX()) +
1681 (y
- this->GetY())*(y
- this->GetY()));
1682 ppt
->m_originalDistance
= dist
;
1683 ppt
->m_originalSize
.x
= bound_x
;
1684 ppt
->m_originalSize
.y
= bound_y
;
1686 if (ppt
->m_originalDistance
== 0.0) ppt
->m_originalDistance
= (double) 0.0001;
1688 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1689 dc
.SetPen(dottedPen
);
1690 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1692 #if 0 // keys & KEY_CTRL)
1694 // TODO: mend this code. Currently we rely on altering the
1695 // actual points, but we should assume we're not, as per
1696 // the normal sizing case.
1697 m_canvas
->Snap(&x
, &y
);
1700 ppt
->m_polygonVertex
->x
= x
- this->GetX();
1701 ppt
->m_polygonVertex
->y
= y
- this->GetY();
1704 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1705 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1709 ppt
->CalculateNewSize(x
, y
);
1713 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1714 ppt
->GetNewSize().x
, ppt
->GetNewSize().y
);
1716 m_canvas
->CaptureMouse();
1719 void wxPolygonShape::OnSizingEndDragLeft(wxControlPoint
* pt
, double WXUNUSED(x
), double WXUNUSED(y
), int keys
, int WXUNUSED(attachment
))
1721 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
1723 wxClientDC
dc(GetCanvas());
1724 GetCanvas()->PrepareDC(dc
);
1726 m_canvas
->ReleaseMouse();
1727 dc
.SetLogicalFunction(wxCOPY
);
1729 // If we're changing shape, must reset the original points
1730 if (keys
& KEY_CTRL
)
1732 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1733 ((wxPolygonShape
*)this)->UpdateOriginalPoints();
1737 SetSize(ppt
->GetNewSize().x
, ppt
->GetNewSize().y
);
1740 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1741 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1744 this->ResetControlPoints();
1745 this->Move(dc
, this->GetX(), this->GetY());
1746 if (!m_canvas
->GetQuickEditMode()) m_canvas
->Redraw(dc
);
1753 IMPLEMENT_DYNAMIC_CLASS(wxShapeRegion
, wxObject
)
1755 wxShapeRegion::wxShapeRegion()
1757 m_regionText
= wxEmptyString
;
1758 m_font
= g_oglNormalFont
;
1766 m_regionProportionX
= -1.0;
1767 m_regionProportionY
= -1.0;
1768 m_formatMode
= FORMAT_CENTRE_HORIZ
| FORMAT_CENTRE_VERT
;
1769 m_regionName
= wxEmptyString
;
1770 m_textColour
= wxT("BLACK");
1771 m_penColour
= wxT("BLACK");
1772 m_penStyle
= wxSOLID
;
1773 m_actualColourObject
= wxTheColourDatabase
->Find(wxT("BLACK"));
1774 m_actualPenObject
= NULL
;
1777 wxShapeRegion::wxShapeRegion(wxShapeRegion
& region
)
1779 m_regionText
= region
.m_regionText
;
1780 m_regionName
= region
.m_regionName
;
1781 m_textColour
= region
.m_textColour
;
1783 m_font
= region
.m_font
;
1784 m_minHeight
= region
.m_minHeight
;
1785 m_minWidth
= region
.m_minWidth
;
1786 m_width
= region
.m_width
;
1787 m_height
= region
.m_height
;
1791 m_regionProportionX
= region
.m_regionProportionX
;
1792 m_regionProportionY
= region
.m_regionProportionY
;
1793 m_formatMode
= region
.m_formatMode
;
1794 m_actualColourObject
= region
.m_actualColourObject
;
1795 m_actualPenObject
= NULL
;
1796 m_penStyle
= region
.m_penStyle
;
1797 m_penColour
= region
.m_penColour
;
1800 wxObjectList::compatibility_iterator node
= region
.m_formattedText
.GetFirst();
1803 wxShapeTextLine
*line
= (wxShapeTextLine
*)node
->GetData();
1804 wxShapeTextLine
*new_line
=
1805 new wxShapeTextLine(line
->GetX(), line
->GetY(), line
->GetText());
1806 m_formattedText
.Append(new_line
);
1807 node
= node
->GetNext();
1811 wxShapeRegion::~wxShapeRegion()
1816 void wxShapeRegion::ClearText()
1818 wxObjectList::compatibility_iterator node
= m_formattedText
.GetFirst();
1821 wxShapeTextLine
*line
= (wxShapeTextLine
*)node
->GetData();
1822 wxObjectList::compatibility_iterator next
= node
->GetNext();
1824 m_formattedText
.Erase(node
);
1829 void wxShapeRegion::SetFont(wxFont
*f
)
1834 void wxShapeRegion::SetMinSize(double w
, double h
)
1840 void wxShapeRegion::SetSize(double w
, double h
)
1846 void wxShapeRegion::SetPosition(double xp
, double yp
)
1852 void wxShapeRegion::SetProportions(double xp
, double yp
)
1854 m_regionProportionX
= xp
;
1855 m_regionProportionY
= yp
;
1858 void wxShapeRegion::SetFormatMode(int mode
)
1860 m_formatMode
= mode
;
1863 void wxShapeRegion::SetColour(const wxString
& col
)
1866 m_actualColourObject
= col
;
1869 wxColour
wxShapeRegion::GetActualColourObject()
1871 m_actualColourObject
= wxTheColourDatabase
->Find(GetColour());
1872 return m_actualColourObject
;
1875 void wxShapeRegion::SetPenColour(const wxString
& col
)
1878 m_actualPenObject
= NULL
;
1881 // Returns NULL if the pen is invisible
1882 // (different to pen being transparent; indicates that
1883 // region boundary should not be drawn.)
1884 wxPen
*wxShapeRegion::GetActualPen()
1886 if (m_actualPenObject
)
1887 return m_actualPenObject
;
1889 if (!m_penColour
) return NULL
;
1890 if (m_penColour
== wxT("Invisible"))
1892 m_actualPenObject
= wxThePenList
->FindOrCreatePen(m_penColour
, 1, m_penStyle
);
1893 return m_actualPenObject
;