1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Basic OGL classes (2)
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
24 #include "wx/deprecated/wxexpr.h"
35 #include "wx/ogl/ogl.h"
38 // Control point types
39 // Rectangle and most other shapes
40 #define CONTROL_POINT_VERTICAL 1
41 #define CONTROL_POINT_HORIZONTAL 2
42 #define CONTROL_POINT_DIAGONAL 3
45 #define CONTROL_POINT_ENDPOINT_TO 4
46 #define CONTROL_POINT_ENDPOINT_FROM 5
47 #define CONTROL_POINT_LINE 6
49 // Two stage construction: need to call Create
50 IMPLEMENT_DYNAMIC_CLASS(wxPolygonShape
, wxShape
)
52 wxPolygonShape::wxPolygonShape()
55 m_originalPoints
= NULL
;
58 void wxPolygonShape::Create(wxList
*the_points
)
64 m_originalPoints
= new wxList
;
65 m_points
= new wxList
;
69 m_originalPoints
= the_points
;
71 // Duplicate the list of points
72 m_points
= new wxList
;
74 wxObjectList::compatibility_iterator node
= the_points
->GetFirst();
77 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
78 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
79 m_points
->Append((wxObject
*) new_point
);
80 node
= node
->GetNext();
82 CalculateBoundingBox();
83 m_originalWidth
= m_boundWidth
;
84 m_originalHeight
= m_boundHeight
;
85 SetDefaultRegionSize();
89 wxPolygonShape::~wxPolygonShape()
94 void wxPolygonShape::ClearPoints()
98 wxObjectList::compatibility_iterator node
= m_points
->GetFirst();
101 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
103 m_points
->Erase(node
);
104 node
= m_points
->GetFirst();
109 if (m_originalPoints
)
111 wxObjectList::compatibility_iterator node
= m_originalPoints
->GetFirst();
114 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
116 m_originalPoints
->Erase(node
);
117 node
= m_originalPoints
->GetFirst();
119 delete m_originalPoints
;
120 m_originalPoints
= NULL
;
125 // Width and height. Centre of object is centre of box.
126 void wxPolygonShape::GetBoundingBoxMin(double *width
, double *height
)
128 *width
= m_boundWidth
;
129 *height
= m_boundHeight
;
132 void wxPolygonShape::CalculateBoundingBox()
134 // Calculate bounding box at construction (and presumably resize) time
136 double right
= -10000;
138 double bottom
= -10000;
140 wxObjectList::compatibility_iterator node
= m_points
->GetFirst();
143 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
144 if (point
->x
< left
) left
= point
->x
;
145 if (point
->x
> right
) right
= point
->x
;
147 if (point
->y
< top
) top
= point
->y
;
148 if (point
->y
> bottom
) bottom
= point
->y
;
150 node
= node
->GetNext();
152 m_boundWidth
= right
- left
;
153 m_boundHeight
= bottom
- top
;
156 // Recalculates the centre of the polygon, and
157 // readjusts the point offsets accordingly.
158 // Necessary since the centre of the polygon
159 // is expected to be the real centre of the bounding
161 void wxPolygonShape::CalculatePolygonCentre()
164 double right
= -10000;
166 double bottom
= -10000;
168 wxObjectList::compatibility_iterator node
= m_points
->GetFirst();
171 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
172 if (point
->x
< left
) left
= point
->x
;
173 if (point
->x
> right
) right
= point
->x
;
175 if (point
->y
< top
) top
= point
->y
;
176 if (point
->y
> bottom
) bottom
= point
->y
;
178 node
= node
->GetNext();
180 double bwidth
= right
- left
;
181 double bheight
= bottom
- top
;
183 double newCentreX
= (double)(left
+ (bwidth
/2.0));
184 double newCentreY
= (double)(top
+ (bheight
/2.0));
186 node
= m_points
->GetFirst();
189 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
190 point
->x
-= newCentreX
;
191 point
->y
-= newCentreY
;
192 node
= node
->GetNext();
194 m_xpos
+= newCentreX
;
195 m_ypos
+= newCentreY
;
198 bool PolylineHitTest(double n
, double xvec
[], double yvec
[],
199 double x1
, double y1
, double x2
, double y2
)
203 double lastx
= xvec
[0];
204 double lasty
= yvec
[0];
206 double min_ratio
= 1.0;
210 for (i
= 1; i
< n
; i
++)
212 oglCheckLineIntersection(x1
, y1
, x2
, y2
, lastx
, lasty
, xvec
[i
], yvec
[i
],
213 &line_ratio
, &other_ratio
);
214 if (line_ratio
!= 1.0)
219 if (line_ratio
< min_ratio
)
220 min_ratio
= line_ratio
;
223 // Do last (implicit) line if last and first doubles are not identical
224 if (!(xvec
[0] == lastx
&& yvec
[0] == lasty
))
226 oglCheckLineIntersection(x1
, y1
, x2
, y2
, lastx
, lasty
, xvec
[0], yvec
[0],
227 &line_ratio
, &other_ratio
);
228 if (line_ratio
!= 1.0)
235 bool wxPolygonShape::HitTest(double x
, double y
, int *attachment
, double *distance
)
237 // Imagine four lines radiating from this point. If all of these lines hit the polygon,
238 // we're inside it, otherwise we're not. Obviously we'd need more radiating lines
239 // to be sure of correct results for very strange (concave) shapes.
240 double endPointsX
[4];
241 double endPointsY
[4];
244 endPointsY
[0] = (double)(y
- 1000.0);
246 endPointsX
[1] = (double)(x
+ 1000.0);
250 endPointsY
[2] = (double)(y
+ 1000.0);
252 endPointsX
[3] = (double)(x
- 1000.0);
255 // Store polygon points in an array
256 int np
= m_points
->GetCount();
257 double *xpoints
= new double[np
];
258 double *ypoints
= new double[np
];
259 wxObjectList::compatibility_iterator node
= m_points
->GetFirst();
263 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
264 xpoints
[i
] = point
->x
+ m_xpos
;
265 ypoints
[i
] = point
->y
+ m_ypos
;
266 node
= node
->GetNext();
270 // We assume it's inside the polygon UNLESS one or more
271 // lines don't hit the outline.
272 bool isContained
= true;
275 for (i
= 0; i
< noPoints
; i
++)
277 if (!PolylineHitTest(np
, xpoints
, ypoints
, x
, y
, endPointsX
[i
], endPointsY
[i
]))
282 ClipsErrorFunction("It's a hit!\n");
284 ClipsErrorFunction("No hit.\n");
292 int nearest_attachment
= 0;
294 // If a hit, check the attachment points within the object.
295 int n
= GetNumberOfAttachments();
296 double nearest
= 999999.0;
298 for (i
= 0; i
< n
; i
++)
301 if (GetAttachmentPositionEdge(i
, &xp
, &yp
))
303 double l
= (double)sqrt(((xp
- x
) * (xp
- x
)) +
304 ((yp
- y
) * (yp
- y
)));
308 nearest_attachment
= i
;
312 *attachment
= nearest_attachment
;
317 // Really need to be able to reset the shape! Otherwise, if the
318 // points ever go to zero, we've lost it, and can't resize.
319 void wxPolygonShape::SetSize(double new_width
, double new_height
, bool WXUNUSED(recursive
))
321 SetAttachmentSize(new_width
, new_height
);
323 // Multiply all points by proportion of new size to old size
324 double x_proportion
= (double)(fabs(new_width
/m_originalWidth
));
325 double y_proportion
= (double)(fabs(new_height
/m_originalHeight
));
327 wxObjectList::compatibility_iterator node
= m_points
->GetFirst();
328 wxObjectList::compatibility_iterator original_node
= m_originalPoints
->GetFirst();
329 while (node
&& original_node
)
331 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
332 wxRealPoint
*original_point
= (wxRealPoint
*)original_node
->GetData();
334 point
->x
= (original_point
->x
* x_proportion
);
335 point
->y
= (original_point
->y
* y_proportion
);
337 node
= node
->GetNext();
338 original_node
= original_node
->GetNext();
341 // CalculateBoundingBox();
342 m_boundWidth
= (double)fabs(new_width
);
343 m_boundHeight
= (double)fabs(new_height
);
344 SetDefaultRegionSize();
347 // Make the original points the same as the working points
348 void wxPolygonShape::UpdateOriginalPoints()
350 if (!m_originalPoints
) m_originalPoints
= new wxList
;
351 wxObjectList::compatibility_iterator original_node
= m_originalPoints
->GetFirst();
352 while (original_node
)
354 wxObjectList::compatibility_iterator next_node
= original_node
->GetNext();
355 wxRealPoint
*original_point
= (wxRealPoint
*)original_node
->GetData();
356 delete original_point
;
357 m_originalPoints
->Erase(original_node
);
359 original_node
= next_node
;
362 wxObjectList::compatibility_iterator node
= m_points
->GetFirst();
365 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
366 wxRealPoint
*original_point
= new wxRealPoint(point
->x
, point
->y
);
367 m_originalPoints
->Append((wxObject
*) original_point
);
369 node
= node
->GetNext();
371 CalculateBoundingBox();
372 m_originalWidth
= m_boundWidth
;
373 m_originalHeight
= m_boundHeight
;
376 void wxPolygonShape::AddPolygonPoint(int pos
)
378 wxObjectList::compatibility_iterator node
= m_points
->Item(pos
);
379 if (!node
) node
= m_points
->GetFirst();
380 wxRealPoint
*firstPoint
= (wxRealPoint
*)node
->GetData();
382 wxObjectList::compatibility_iterator node2
= m_points
->Item(pos
+ 1);
383 if (!node2
) node2
= m_points
->GetFirst();
384 wxRealPoint
*secondPoint
= (wxRealPoint
*)node2
->GetData();
386 double x
= (double)((secondPoint
->x
- firstPoint
->x
)/2.0 + firstPoint
->x
);
387 double y
= (double)((secondPoint
->y
- firstPoint
->y
)/2.0 + firstPoint
->y
);
388 wxRealPoint
*point
= new wxRealPoint(x
, y
);
390 if (pos
>= (int) (m_points
->GetCount() - 1))
391 m_points
->Append((wxObject
*) point
);
393 m_points
->Insert(node2
, (wxObject
*) point
);
395 UpdateOriginalPoints();
399 DeleteControlPoints();
404 void wxPolygonShape::DeletePolygonPoint(int pos
)
406 wxObjectList::compatibility_iterator node
= m_points
->Item(pos
);
409 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
411 m_points
->Erase(node
);
412 UpdateOriginalPoints();
415 DeleteControlPoints();
421 // Assume (x1, y1) is centre of box (most generally, line end at box)
422 bool wxPolygonShape::GetPerimeterPoint(double x1
, double y1
,
423 double x2
, double y2
,
424 double *x3
, double *y3
)
426 int n
= m_points
->GetCount();
428 // First check for situation where the line is vertical,
429 // and we would want to connect to a point on that vertical --
430 // oglFindEndForPolyline can't cope with this (the arrow
431 // gets drawn to the wrong place).
432 if ((m_attachmentMode
== ATTACHMENT_MODE_NONE
) && (x1
== x2
))
434 // Look for the point we'd be connecting to. This is
436 wxObjectList::compatibility_iterator node
= m_points
->GetFirst();
439 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
442 if ((y2
> y1
) && (point
->y
> 0.0))
444 *x3
= point
->x
+ m_xpos
;
445 *y3
= point
->y
+ m_ypos
;
448 else if ((y2
< y1
) && (point
->y
< 0.0))
450 *x3
= point
->x
+ m_xpos
;
451 *y3
= point
->y
+ m_ypos
;
455 node
= node
->GetNext();
459 double *xpoints
= new double[n
];
460 double *ypoints
= new double[n
];
462 wxObjectList::compatibility_iterator node
= m_points
->GetFirst();
466 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
467 xpoints
[i
] = point
->x
+ m_xpos
;
468 ypoints
[i
] = point
->y
+ m_ypos
;
469 node
= node
->GetNext();
473 oglFindEndForPolyline(n
, xpoints
, ypoints
,
474 x1
, y1
, x2
, y2
, x3
, y3
);
482 void wxPolygonShape::OnDraw(wxDC
& dc
)
484 int n
= m_points
->GetCount();
485 wxPoint
*intPoints
= new wxPoint
[n
];
487 for (i
= 0; i
< n
; i
++)
489 wxRealPoint
* point
= (wxRealPoint
*) m_points
->Item(i
)->GetData();
490 intPoints
[i
].x
= WXROUND(point
->x
);
491 intPoints
[i
].y
= WXROUND(point
->y
);
494 if (m_shadowMode
!= SHADOW_NONE
)
497 dc
.SetBrush(* m_shadowBrush
);
498 dc
.SetPen(* g_oglTransparentPen
);
500 dc
.DrawPolygon(n
, intPoints
, WXROUND(m_xpos
+ m_shadowOffsetX
), WXROUND(m_ypos
+ m_shadowOffsetY
));
505 if (m_pen
->GetWidth() == 0)
506 dc
.SetPen(* g_oglTransparentPen
);
511 dc
.SetBrush(* m_brush
);
512 dc
.DrawPolygon(n
, intPoints
, WXROUND(m_xpos
), WXROUND(m_ypos
));
517 void wxPolygonShape::OnDrawOutline(wxDC
& dc
, double x
, double y
, double w
, double h
)
519 dc
.SetBrush(* wxTRANSPARENT_BRUSH
);
520 // Multiply all points by proportion of new size to old size
521 double x_proportion
= (double)(fabs(w
/m_originalWidth
));
522 double y_proportion
= (double)(fabs(h
/m_originalHeight
));
524 int n
= m_originalPoints
->GetCount();
525 wxPoint
*intPoints
= new wxPoint
[n
];
527 for (i
= 0; i
< n
; i
++)
529 wxRealPoint
* point
= (wxRealPoint
*) m_originalPoints
->Item(i
)->GetData();
530 intPoints
[i
].x
= WXROUND(x_proportion
* point
->x
);
531 intPoints
[i
].y
= WXROUND(y_proportion
* point
->y
);
533 dc
.DrawPolygon(n
, intPoints
, WXROUND(x
), WXROUND(y
));
537 // Make as many control points as there are vertices.
538 void wxPolygonShape::MakeControlPoints()
540 wxObjectList::compatibility_iterator node
= m_points
->GetFirst();
543 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
544 wxPolygonControlPoint
*control
= new wxPolygonControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
,
545 point
, point
->x
, point
->y
);
546 m_canvas
->AddShape(control
);
547 m_controlPoints
.Append(control
);
548 node
= node
->GetNext();
552 void wxPolygonShape::ResetControlPoints()
554 wxObjectList::compatibility_iterator node
= m_points
->GetFirst();
555 wxObjectList::compatibility_iterator controlPointNode
= m_controlPoints
.GetFirst();
556 while (node
&& controlPointNode
)
558 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
559 wxPolygonControlPoint
*controlPoint
= (wxPolygonControlPoint
*)controlPointNode
->GetData();
561 controlPoint
->m_xoffset
= point
->x
;
562 controlPoint
->m_yoffset
= point
->y
;
563 controlPoint
->m_polygonVertex
= point
;
565 node
= node
->GetNext();
566 controlPointNode
= controlPointNode
->GetNext();
572 void wxPolygonShape::WriteAttributes(wxExpr
*clause
)
574 wxShape::WriteAttributes(clause
);
576 clause
->AddAttributeValue(wxT("x"), m_xpos
);
577 clause
->AddAttributeValue(wxT("y"), m_ypos
);
579 // Make a list of lists for the coordinates
580 wxExpr
*list
= new wxExpr(wxExprList
);
581 wxObjectList::compatibility_iterator node
= m_points
->GetFirst();
584 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
585 wxExpr
*point_list
= new wxExpr(wxExprList
);
586 wxExpr
*x_expr
= new wxExpr((double)point
->x
);
587 wxExpr
*y_expr
= new wxExpr((double)point
->y
);
589 point_list
->Append(x_expr
);
590 point_list
->Append(y_expr
);
591 list
->Append(point_list
);
593 node
= node
->GetNext();
595 clause
->AddAttributeValue(wxT("points"), list
);
597 // Save the original (unscaled) points
598 list
= new wxExpr(wxExprList
);
599 node
= m_originalPoints
->GetFirst();
602 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
603 wxExpr
*point_list
= new wxExpr(wxExprList
);
604 wxExpr
*x_expr
= new wxExpr((double) point
->x
);
605 wxExpr
*y_expr
= new wxExpr((double) point
->y
);
606 point_list
->Append(x_expr
);
607 point_list
->Append(y_expr
);
608 list
->Append(point_list
);
610 node
= node
->GetNext();
612 clause
->AddAttributeValue(wxT("m_originalPoints"), list
);
615 void wxPolygonShape::ReadAttributes(wxExpr
*clause
)
617 wxShape::ReadAttributes(clause
);
619 // Read a list of lists
620 m_points
= new wxList
;
621 m_originalPoints
= new wxList
;
623 wxExpr
*points_list
= NULL
;
624 clause
->AssignAttributeValue(wxT("points"), &points_list
);
626 // If no points_list, don't crash!! Assume a diamond instead.
627 double the_height
= 100.0;
628 double the_width
= 100.0;
631 wxRealPoint
*point
= new wxRealPoint(0.0, (-the_height
/2));
632 m_points
->Append((wxObject
*) point
);
634 point
= new wxRealPoint((the_width
/2), 0.0);
635 m_points
->Append((wxObject
*) point
);
637 point
= new wxRealPoint(0.0, (the_height
/2));
638 m_points
->Append((wxObject
*) point
);
640 point
= new wxRealPoint((-the_width
/2), 0.0);
641 m_points
->Append((wxObject
*) point
);
643 point
= new wxRealPoint(0.0, (-the_height
/2));
644 m_points
->Append((wxObject
*) point
);
648 wxExpr
*node
= points_list
->value
.first
;
652 wxExpr
*xexpr
= node
->value
.first
;
653 long x
= xexpr
->IntegerValue();
655 wxExpr
*yexpr
= xexpr
->next
;
656 long y
= yexpr
->IntegerValue();
658 wxRealPoint
*point
= new wxRealPoint((double)x
, (double)y
);
659 m_points
->Append((wxObject
*) point
);
666 clause
->AssignAttributeValue(wxT("m_originalPoints"), &points_list
);
668 // If no points_list, don't crash!! Assume a diamond instead.
671 wxRealPoint
*point
= new wxRealPoint(0.0, (-the_height
/2));
672 m_originalPoints
->Append((wxObject
*) point
);
674 point
= new wxRealPoint((the_width
/2), 0.0);
675 m_originalPoints
->Append((wxObject
*) point
);
677 point
= new wxRealPoint(0.0, (the_height
/2));
678 m_originalPoints
->Append((wxObject
*) point
);
680 point
= new wxRealPoint((-the_width
/2), 0.0);
681 m_originalPoints
->Append((wxObject
*) point
);
683 point
= new wxRealPoint(0.0, (-the_height
/2));
684 m_originalPoints
->Append((wxObject
*) point
);
686 m_originalWidth
= the_width
;
687 m_originalHeight
= the_height
;
691 wxExpr
*node
= points_list
->value
.first
;
694 double max_x
= -1000;
695 double max_y
= -1000;
698 wxExpr
*xexpr
= node
->value
.first
;
699 long x
= xexpr
->IntegerValue();
701 wxExpr
*yexpr
= xexpr
->next
;
702 long y
= yexpr
->IntegerValue();
704 wxRealPoint
*point
= new wxRealPoint((double)x
, (double)y
);
705 m_originalPoints
->Append((wxObject
*) point
);
718 m_originalWidth
= max_x
- min_x
;
719 m_originalHeight
= max_y
- min_y
;
722 CalculateBoundingBox();
726 void wxPolygonShape::Copy(wxShape
& copy
)
730 wxASSERT( copy
.IsKindOf(CLASSINFO(wxPolygonShape
)) );
732 wxPolygonShape
& polyCopy
= (wxPolygonShape
&) copy
;
734 polyCopy
.ClearPoints();
736 polyCopy
.m_points
= new wxList
;
737 polyCopy
.m_originalPoints
= new wxList
;
739 wxObjectList::compatibility_iterator node
= m_points
->GetFirst();
742 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
743 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
744 polyCopy
.m_points
->Append((wxObject
*) new_point
);
745 node
= node
->GetNext();
747 node
= m_originalPoints
->GetFirst();
750 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
751 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
752 polyCopy
.m_originalPoints
->Append((wxObject
*) new_point
);
753 node
= node
->GetNext();
755 polyCopy
.m_boundWidth
= m_boundWidth
;
756 polyCopy
.m_boundHeight
= m_boundHeight
;
757 polyCopy
.m_originalWidth
= m_originalWidth
;
758 polyCopy
.m_originalHeight
= m_originalHeight
;
761 int wxPolygonShape::GetNumberOfAttachments() const
763 int maxN
= (m_points
? (m_points
->GetCount() - 1) : 0);
764 wxObjectList::compatibility_iterator node
= m_attachmentPoints
.GetFirst();
767 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->GetData();
768 if (point
->m_id
> maxN
)
770 node
= node
->GetNext();
775 bool wxPolygonShape::GetAttachmentPosition(int attachment
, double *x
, double *y
,
776 int nth
, int no_arcs
, wxLineShape
*line
)
778 if ((m_attachmentMode
== ATTACHMENT_MODE_EDGE
) && m_points
&& attachment
< (int) m_points
->GetCount())
780 wxRealPoint
*point
= (wxRealPoint
*)m_points
->Item(attachment
)->GetData();
781 *x
= point
->x
+ m_xpos
;
782 *y
= point
->y
+ m_ypos
;
786 { return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
); }
789 bool wxPolygonShape::AttachmentIsValid(int attachment
) const
794 if ((attachment
>= 0) && (attachment
< (int) m_points
->GetCount()))
797 wxObjectList::compatibility_iterator node
= m_attachmentPoints
.GetFirst();
800 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->GetData();
801 if (point
->m_id
== attachment
)
803 node
= node
->GetNext();
808 // Rotate about the given axis by the given amount in radians
809 void wxPolygonShape::Rotate(double x
, double y
, double theta
)
811 double actualTheta
= theta
-m_rotation
;
813 // Rotate attachment points
814 double sinTheta
= (double)sin(actualTheta
);
815 double cosTheta
= (double)cos(actualTheta
);
816 wxObjectList::compatibility_iterator node
= m_attachmentPoints
.GetFirst();
819 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->GetData();
820 double x1
= point
->m_x
;
821 double y1
= point
->m_y
;
822 point
->m_x
= x1
*cosTheta
- y1
*sinTheta
+ x
*(1.0 - cosTheta
) + y
*sinTheta
;
823 point
->m_y
= x1
*sinTheta
+ y1
*cosTheta
+ y
*(1.0 - cosTheta
) + x
*sinTheta
;
824 node
= node
->GetNext();
827 node
= m_points
->GetFirst();
830 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
831 double x1
= point
->x
;
832 double y1
= point
->y
;
833 point
->x
= x1
*cosTheta
- y1
*sinTheta
+ x
*(1.0 - cosTheta
) + y
*sinTheta
;
834 point
->y
= x1
*sinTheta
+ y1
*cosTheta
+ y
*(1.0 - cosTheta
) + x
*sinTheta
;
835 node
= node
->GetNext();
837 node
= m_originalPoints
->GetFirst();
840 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
841 double x1
= point
->x
;
842 double y1
= point
->y
;
843 point
->x
= x1
*cosTheta
- y1
*sinTheta
+ x
*(1.0 - cosTheta
) + y
*sinTheta
;
844 point
->y
= x1
*sinTheta
+ y1
*cosTheta
+ y
*(1.0 - cosTheta
) + x
*sinTheta
;
845 node
= node
->GetNext();
850 CalculatePolygonCentre();
851 CalculateBoundingBox();
852 ResetControlPoints();
857 IMPLEMENT_DYNAMIC_CLASS(wxRectangleShape
, wxShape
)
859 wxRectangleShape::wxRectangleShape(double w
, double h
)
861 m_width
= w
; m_height
= h
; m_cornerRadius
= 0.0;
862 SetDefaultRegionSize();
865 void wxRectangleShape::OnDraw(wxDC
& dc
)
867 double x1
= (double)(m_xpos
- m_width
/2.0);
868 double y1
= (double)(m_ypos
- m_height
/2.0);
870 if (m_shadowMode
!= SHADOW_NONE
)
873 dc
.SetBrush(* m_shadowBrush
);
874 dc
.SetPen(* g_oglTransparentPen
);
876 if (m_cornerRadius
!= 0.0)
877 dc
.DrawRoundedRectangle(WXROUND(x1
+ m_shadowOffsetX
), WXROUND(y1
+ m_shadowOffsetY
),
878 WXROUND(m_width
), WXROUND(m_height
), m_cornerRadius
);
880 dc
.DrawRectangle(WXROUND(x1
+ m_shadowOffsetX
), WXROUND(y1
+ m_shadowOffsetY
), WXROUND(m_width
), WXROUND(m_height
));
885 if (m_pen
->GetWidth() == 0)
886 dc
.SetPen(* g_oglTransparentPen
);
891 dc
.SetBrush(* m_brush
);
893 if (m_cornerRadius
!= 0.0)
894 dc
.DrawRoundedRectangle(WXROUND(x1
), WXROUND(y1
), WXROUND(m_width
), WXROUND(m_height
), m_cornerRadius
);
896 dc
.DrawRectangle(WXROUND(x1
), WXROUND(y1
), WXROUND(m_width
), WXROUND(m_height
));
899 void wxRectangleShape::GetBoundingBoxMin(double *the_width
, double *the_height
)
901 *the_width
= m_width
;
902 *the_height
= m_height
;
905 void wxRectangleShape::SetSize(double x
, double y
, bool WXUNUSED(recursive
))
907 SetAttachmentSize(x
, y
);
908 m_width
= (double)wxMax(x
, 1.0);
909 m_height
= (double)wxMax(y
, 1.0);
910 SetDefaultRegionSize();
913 void wxRectangleShape::SetCornerRadius(double rad
)
915 m_cornerRadius
= rad
;
918 // Assume (x1, y1) is centre of box (most generally, line end at box)
919 bool wxRectangleShape::GetPerimeterPoint(double WXUNUSED(x1
), double WXUNUSED(y1
),
920 double x2
, double y2
,
921 double *x3
, double *y3
)
923 double bound_x
, bound_y
;
924 GetBoundingBoxMax(&bound_x
, &bound_y
);
925 oglFindEndForBox(bound_x
, bound_y
, m_xpos
, m_ypos
, x2
, y2
, x3
, y3
);
931 void wxRectangleShape::WriteAttributes(wxExpr
*clause
)
933 wxShape::WriteAttributes(clause
);
934 clause
->AddAttributeValue(wxT("x"), m_xpos
);
935 clause
->AddAttributeValue(wxT("y"), m_ypos
);
937 clause
->AddAttributeValue(wxT("width"), m_width
);
938 clause
->AddAttributeValue(wxT("height"), m_height
);
939 if (m_cornerRadius
!= 0.0)
940 clause
->AddAttributeValue(wxT("corner"), m_cornerRadius
);
943 void wxRectangleShape::ReadAttributes(wxExpr
*clause
)
945 wxShape::ReadAttributes(clause
);
946 clause
->AssignAttributeValue(wxT("width"), &m_width
);
947 clause
->AssignAttributeValue(wxT("height"), &m_height
);
948 clause
->AssignAttributeValue(wxT("corner"), &m_cornerRadius
);
950 // In case we're reading an old file, set the region's size
951 if (m_regions
.GetCount() == 1)
953 wxShapeRegion
*region
= (wxShapeRegion
*)m_regions
.GetFirst()->GetData();
954 region
->SetSize(m_width
, m_height
);
959 void wxRectangleShape::Copy(wxShape
& copy
)
963 wxASSERT( copy
.IsKindOf(CLASSINFO(wxRectangleShape
)) );
965 wxRectangleShape
& rectCopy
= (wxRectangleShape
&) copy
;
966 rectCopy
.m_width
= m_width
;
967 rectCopy
.m_height
= m_height
;
968 rectCopy
.m_cornerRadius
= m_cornerRadius
;
971 int wxRectangleShape::GetNumberOfAttachments() const
973 return wxShape::GetNumberOfAttachments();
977 // There are 4 attachment points on a rectangle - 0 = top, 1 = right, 2 = bottom,
979 bool wxRectangleShape::GetAttachmentPosition(int attachment
, double *x
, double *y
,
980 int nth
, int no_arcs
, wxLineShape
*line
)
982 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
985 // Text object (no box)
987 IMPLEMENT_DYNAMIC_CLASS(wxTextShape
, wxRectangleShape
)
989 wxTextShape::wxTextShape(double width
, double height
):
990 wxRectangleShape(width
, height
)
994 void wxTextShape::OnDraw(wxDC
& WXUNUSED(dc
))
998 void wxTextShape::Copy(wxShape
& copy
)
1000 wxRectangleShape::Copy(copy
);
1004 void wxTextShape::WriteAttributes(wxExpr
*clause
)
1006 wxRectangleShape::WriteAttributes(clause
);
1012 IMPLEMENT_DYNAMIC_CLASS(wxEllipseShape
, wxShape
)
1014 wxEllipseShape::wxEllipseShape(double w
, double h
)
1016 m_width
= w
; m_height
= h
;
1017 SetDefaultRegionSize();
1020 void wxEllipseShape::GetBoundingBoxMin(double *w
, double *h
)
1022 *w
= m_width
; *h
= m_height
;
1025 bool wxEllipseShape::GetPerimeterPoint(double x1
, double y1
,
1026 double x2
, double y2
,
1027 double *x3
, double *y3
)
1029 double bound_x
, bound_y
;
1030 GetBoundingBoxMax(&bound_x
, &bound_y
);
1032 // oglFindEndForBox(bound_x, bound_y, m_xpos, m_ypos, x2, y2, x3, y3);
1033 oglDrawArcToEllipse(m_xpos
, m_ypos
, bound_x
, bound_y
, x2
, y2
, x1
, y1
, x3
, y3
);
1038 void wxEllipseShape::OnDraw(wxDC
& dc
)
1040 if (m_shadowMode
!= SHADOW_NONE
)
1043 dc
.SetBrush(* m_shadowBrush
);
1044 dc
.SetPen(* g_oglTransparentPen
);
1045 dc
.DrawEllipse((long) ((m_xpos
- GetWidth()/2) + m_shadowOffsetX
),
1046 (long) ((m_ypos
- GetHeight()/2) + m_shadowOffsetY
),
1047 (long) GetWidth(), (long) GetHeight());
1052 if (m_pen
->GetWidth() == 0)
1053 dc
.SetPen(* g_oglTransparentPen
);
1058 dc
.SetBrush(* m_brush
);
1059 dc
.DrawEllipse((long) (m_xpos
- GetWidth()/2), (long) (m_ypos
- GetHeight()/2), (long) GetWidth(), (long) GetHeight());
1062 void wxEllipseShape::SetSize(double x
, double y
, bool WXUNUSED(recursive
))
1064 SetAttachmentSize(x
, y
);
1067 SetDefaultRegionSize();
1071 void wxEllipseShape::WriteAttributes(wxExpr
*clause
)
1073 wxShape::WriteAttributes(clause
);
1074 clause
->AddAttributeValue(wxT("x"), m_xpos
);
1075 clause
->AddAttributeValue(wxT("y"), m_ypos
);
1077 clause
->AddAttributeValue(wxT("width"), m_width
);
1078 clause
->AddAttributeValue(wxT("height"), m_height
);
1081 void wxEllipseShape::ReadAttributes(wxExpr
*clause
)
1083 wxShape::ReadAttributes(clause
);
1084 clause
->AssignAttributeValue(wxT("width"), &m_width
);
1085 clause
->AssignAttributeValue(wxT("height"), &m_height
);
1087 // In case we're reading an old file, set the region's size
1088 if (m_regions
.GetCount() == 1)
1090 wxShapeRegion
*region
= (wxShapeRegion
*)m_regions
.GetFirst()->GetData();
1091 region
->SetSize(m_width
, m_height
);
1096 void wxEllipseShape::Copy(wxShape
& copy
)
1098 wxShape::Copy(copy
);
1100 wxASSERT( copy
.IsKindOf(CLASSINFO(wxEllipseShape
)) );
1102 wxEllipseShape
& ellipseCopy
= (wxEllipseShape
&) copy
;
1104 ellipseCopy
.m_width
= m_width
;
1105 ellipseCopy
.m_height
= m_height
;
1108 int wxEllipseShape::GetNumberOfAttachments() const
1110 return wxShape::GetNumberOfAttachments();
1113 // There are 4 attachment points on an ellipse - 0 = top, 1 = right, 2 = bottom,
1115 bool wxEllipseShape::GetAttachmentPosition(int attachment
, double *x
, double *y
,
1116 int nth
, int no_arcs
, wxLineShape
*line
)
1118 if (m_attachmentMode
== ATTACHMENT_MODE_BRANCHING
)
1119 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
1121 if (m_attachmentMode
!= ATTACHMENT_MODE_NONE
)
1123 double top
= (double)(m_ypos
+ m_height
/2.0);
1124 double bottom
= (double)(m_ypos
- m_height
/2.0);
1125 double left
= (double)(m_xpos
- m_width
/2.0);
1126 double right
= (double)(m_xpos
+ m_width
/2.0);
1128 int physicalAttachment
= LogicalToPhysicalAttachment(attachment
);
1130 switch (physicalAttachment
)
1134 if (m_spaceAttachments
)
1135 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
1138 // We now have the point on the bounding box: but get the point on the ellipse
1139 // by imagining a vertical line from (*x, m_ypos - m_height- 500) to (*x, m_ypos) intersecting
1141 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, *x
, (double)(m_ypos
-m_height
-500), *x
, m_ypos
, x
, y
);
1147 if (m_spaceAttachments
)
1148 *y
= bottom
+ (nth
+ 1)*m_height
/(no_arcs
+ 1);
1150 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, (double)(m_xpos
+m_width
+500), *y
, m_xpos
, *y
, x
, y
);
1155 if (m_spaceAttachments
)
1156 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
1159 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, *x
, (double)(m_ypos
+m_height
+500), *x
, m_ypos
, x
, y
);
1165 if (m_spaceAttachments
)
1166 *y
= bottom
+ (nth
+ 1)*m_height
/(no_arcs
+ 1);
1168 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, (double)(m_xpos
-m_width
-500), *y
, m_xpos
, *y
, x
, y
);
1173 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
1179 { *x
= m_xpos
; *y
= m_ypos
; return true; }
1184 IMPLEMENT_DYNAMIC_CLASS(wxCircleShape
, wxEllipseShape
)
1186 wxCircleShape::wxCircleShape(double diameter
):wxEllipseShape(diameter
, diameter
)
1188 SetMaintainAspectRatio(true);
1191 void wxCircleShape::Copy(wxShape
& copy
)
1193 wxEllipseShape::Copy(copy
);
1196 bool wxCircleShape::GetPerimeterPoint(double WXUNUSED(x1
), double WXUNUSED(y1
),
1197 double x2
, double y2
,
1198 double *x3
, double *y3
)
1200 oglFindEndForCircle(m_width
/2,
1201 m_xpos
, m_ypos
, // Centre of circle
1202 x2
, y2
, // Other end of line
1210 double wxControlPoint::sm_controlPointDragStartX
= 0.0;
1211 double wxControlPoint::sm_controlPointDragStartY
= 0.0;
1212 double wxControlPoint::sm_controlPointDragStartWidth
= 0.0;
1213 double wxControlPoint::sm_controlPointDragStartHeight
= 0.0;
1214 double wxControlPoint::sm_controlPointDragEndWidth
= 0.0;
1215 double wxControlPoint::sm_controlPointDragEndHeight
= 0.0;
1216 double wxControlPoint::sm_controlPointDragPosX
= 0.0;
1217 double wxControlPoint::sm_controlPointDragPosY
= 0.0;
1219 IMPLEMENT_DYNAMIC_CLASS(wxControlPoint
, wxRectangleShape
)
1221 wxControlPoint::wxControlPoint(wxShapeCanvas
*theCanvas
, wxShape
*object
, double size
, double the_xoffset
, double the_yoffset
, int the_type
):wxRectangleShape(size
, size
)
1223 m_canvas
= theCanvas
;
1225 m_xoffset
= the_xoffset
;
1226 m_yoffset
= the_yoffset
;
1228 SetPen(g_oglBlackForegroundPen
);
1229 SetBrush(wxBLACK_BRUSH
);
1232 m_eraseObject
= true;
1235 wxControlPoint::~wxControlPoint()
1239 // Don't even attempt to draw any text - waste of time!
1240 void wxControlPoint::OnDrawContents(wxDC
& WXUNUSED(dc
))
1244 void wxControlPoint::OnDraw(wxDC
& dc
)
1246 m_xpos
= m_shape
->GetX() + m_xoffset
;
1247 m_ypos
= m_shape
->GetY() + m_yoffset
;
1248 wxRectangleShape::OnDraw(dc
);
1251 void wxControlPoint::OnErase(wxDC
& dc
)
1253 wxRectangleShape::OnErase(dc
);
1256 // Implement resizing of canvas object
1257 void wxControlPoint::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
1259 m_shape
->GetEventHandler()->OnSizingDragLeft(this, draw
, x
, y
, keys
, attachment
);
1262 void wxControlPoint::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
1264 m_shape
->GetEventHandler()->OnSizingBeginDragLeft(this, x
, y
, keys
, attachment
);
1267 void wxControlPoint::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
1269 m_shape
->GetEventHandler()->OnSizingEndDragLeft(this, x
, y
, keys
, attachment
);
1272 int wxControlPoint::GetNumberOfAttachments() const
1277 bool wxControlPoint::GetAttachmentPosition(int WXUNUSED(attachment
), double *x
, double *y
,
1278 int WXUNUSED(nth
), int WXUNUSED(no_arcs
), wxLineShape
*WXUNUSED(line
))
1280 *x
= m_xpos
; *y
= m_ypos
;
1284 // Control points ('handles') redirect control to the actual shape, to make it easier
1285 // to override sizing behaviour.
1286 void wxShape::OnSizingDragLeft(wxControlPoint
* pt
, bool WXUNUSED(draw
), double x
, double y
, int keys
, int WXUNUSED(attachment
))
1290 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1292 wxClientDC
dc(GetCanvas());
1293 GetCanvas()->PrepareDC(dc
);
1295 dc
.SetLogicalFunction(OGLRBLF
);
1297 wxPen
dottedPen(*wxBLACK
, 1, wxDOT
);
1298 dc
.SetPen(dottedPen
);
1299 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1301 if (this->GetCentreResize())
1303 // Maintain the same centre point.
1304 double new_width
= (double)(2.0*fabs(x
- this->GetX()));
1305 double new_height
= (double)(2.0*fabs(y
- this->GetY()));
1307 // Constrain sizing according to what control point you're dragging
1308 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1310 if (GetMaintainAspectRatio())
1312 new_height
= bound_y
*(new_width
/bound_x
);
1315 new_height
= bound_y
;
1317 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1319 if (GetMaintainAspectRatio())
1321 new_width
= bound_x
*(new_height
/bound_y
);
1324 new_width
= bound_x
;
1326 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& (keys
& KEY_SHIFT
))
1327 new_height
= bound_y
*(new_width
/bound_x
);
1329 if (this->GetFixedWidth())
1330 new_width
= bound_x
;
1332 if (this->GetFixedHeight())
1333 new_height
= bound_y
;
1335 pt
->sm_controlPointDragEndWidth
= new_width
;
1336 pt
->sm_controlPointDragEndHeight
= new_height
;
1338 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1339 new_width
, new_height
);
1343 // Don't maintain the same centre point!
1344 double newX1
= wxMin(pt
->sm_controlPointDragStartX
, x
);
1345 double newY1
= wxMin(pt
->sm_controlPointDragStartY
, y
);
1346 double newX2
= wxMax(pt
->sm_controlPointDragStartX
, x
);
1347 double newY2
= wxMax(pt
->sm_controlPointDragStartY
, y
);
1348 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1350 newY1
= pt
->sm_controlPointDragStartY
;
1351 newY2
= newY1
+ pt
->sm_controlPointDragStartHeight
;
1353 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1355 newX1
= pt
->sm_controlPointDragStartX
;
1356 newX2
= newX1
+ pt
->sm_controlPointDragStartWidth
;
1358 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& ((keys
& KEY_SHIFT
) || GetMaintainAspectRatio()))
1360 double newH
= (double)((newX2
- newX1
)*(pt
->sm_controlPointDragStartHeight
/pt
->sm_controlPointDragStartWidth
));
1361 if (GetY() > pt
->sm_controlPointDragStartY
)
1362 newY2
= (double)(newY1
+ newH
);
1364 newY1
= (double)(newY2
- newH
);
1366 double newWidth
= (double)(newX2
- newX1
);
1367 double newHeight
= (double)(newY2
- newY1
);
1369 if (pt
->m_type
== CONTROL_POINT_VERTICAL
&& GetMaintainAspectRatio())
1371 newWidth
= bound_x
* (newHeight
/bound_y
) ;
1374 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
&& GetMaintainAspectRatio())
1376 newHeight
= bound_y
* (newWidth
/bound_x
) ;
1379 pt
->sm_controlPointDragPosX
= (double)(newX1
+ (newWidth
/2.0));
1380 pt
->sm_controlPointDragPosY
= (double)(newY1
+ (newHeight
/2.0));
1381 if (this->GetFixedWidth())
1384 if (this->GetFixedHeight())
1385 newHeight
= bound_y
;
1387 pt
->sm_controlPointDragEndWidth
= newWidth
;
1388 pt
->sm_controlPointDragEndHeight
= newHeight
;
1389 this->GetEventHandler()->OnDrawOutline(dc
, pt
->sm_controlPointDragPosX
, pt
->sm_controlPointDragPosY
, newWidth
, newHeight
);
1393 void wxShape::OnSizingBeginDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int WXUNUSED(attachment
))
1395 m_canvas
->CaptureMouse();
1397 wxClientDC
dc(GetCanvas());
1398 GetCanvas()->PrepareDC(dc
);
1400 if (pt->m_eraseObject)
1404 dc
.SetLogicalFunction(OGLRBLF
);
1408 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1409 this->GetEventHandler()->OnBeginSize(bound_x
, bound_y
);
1411 // Choose the 'opposite corner' of the object as the stationary
1412 // point in case this is non-centring resizing.
1413 if (pt
->GetX() < this->GetX())
1414 pt
->sm_controlPointDragStartX
= (double)(this->GetX() + (bound_x
/2.0));
1416 pt
->sm_controlPointDragStartX
= (double)(this->GetX() - (bound_x
/2.0));
1418 if (pt
->GetY() < this->GetY())
1419 pt
->sm_controlPointDragStartY
= (double)(this->GetY() + (bound_y
/2.0));
1421 pt
->sm_controlPointDragStartY
= (double)(this->GetY() - (bound_y
/2.0));
1423 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1424 pt
->sm_controlPointDragStartY
= (double)(this->GetY() - (bound_y
/2.0));
1425 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1426 pt
->sm_controlPointDragStartX
= (double)(this->GetX() - (bound_x
/2.0));
1428 // We may require the old width and height.
1429 pt
->sm_controlPointDragStartWidth
= bound_x
;
1430 pt
->sm_controlPointDragStartHeight
= bound_y
;
1432 wxPen
dottedPen(*wxBLACK
, 1, wxDOT
);
1433 dc
.SetPen(dottedPen
);
1434 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1436 if (this->GetCentreResize())
1438 double new_width
= (double)(2.0*fabs(x
- this->GetX()));
1439 double new_height
= (double)(2.0*fabs(y
- this->GetY()));
1441 // Constrain sizing according to what control point you're dragging
1442 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1444 if (GetMaintainAspectRatio())
1446 new_height
= bound_y
*(new_width
/bound_x
);
1449 new_height
= bound_y
;
1451 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1453 if (GetMaintainAspectRatio())
1455 new_width
= bound_x
*(new_height
/bound_y
);
1458 new_width
= bound_x
;
1460 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& (keys
& KEY_SHIFT
))
1461 new_height
= bound_y
*(new_width
/bound_x
);
1463 if (this->GetFixedWidth())
1464 new_width
= bound_x
;
1466 if (this->GetFixedHeight())
1467 new_height
= bound_y
;
1469 pt
->sm_controlPointDragEndWidth
= new_width
;
1470 pt
->sm_controlPointDragEndHeight
= new_height
;
1471 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1472 new_width
, new_height
);
1476 // Don't maintain the same centre point!
1477 double newX1
= wxMin(pt
->sm_controlPointDragStartX
, x
);
1478 double newY1
= wxMin(pt
->sm_controlPointDragStartY
, y
);
1479 double newX2
= wxMax(pt
->sm_controlPointDragStartX
, x
);
1480 double newY2
= wxMax(pt
->sm_controlPointDragStartY
, y
);
1481 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1483 newY1
= pt
->sm_controlPointDragStartY
;
1484 newY2
= newY1
+ pt
->sm_controlPointDragStartHeight
;
1486 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1488 newX1
= pt
->sm_controlPointDragStartX
;
1489 newX2
= newX1
+ pt
->sm_controlPointDragStartWidth
;
1491 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& ((keys
& KEY_SHIFT
) || GetMaintainAspectRatio()))
1493 double newH
= (double)((newX2
- newX1
)*(pt
->sm_controlPointDragStartHeight
/pt
->sm_controlPointDragStartWidth
));
1494 if (pt
->GetY() > pt
->sm_controlPointDragStartY
)
1495 newY2
= (double)(newY1
+ newH
);
1497 newY1
= (double)(newY2
- newH
);
1499 double newWidth
= (double)(newX2
- newX1
);
1500 double newHeight
= (double)(newY2
- newY1
);
1502 if (pt
->m_type
== CONTROL_POINT_VERTICAL
&& GetMaintainAspectRatio())
1504 newWidth
= bound_x
* (newHeight
/bound_y
) ;
1507 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
&& GetMaintainAspectRatio())
1509 newHeight
= bound_y
* (newWidth
/bound_x
) ;
1512 pt
->sm_controlPointDragPosX
= (double)(newX1
+ (newWidth
/2.0));
1513 pt
->sm_controlPointDragPosY
= (double)(newY1
+ (newHeight
/2.0));
1514 if (this->GetFixedWidth())
1517 if (this->GetFixedHeight())
1518 newHeight
= bound_y
;
1520 pt
->sm_controlPointDragEndWidth
= newWidth
;
1521 pt
->sm_controlPointDragEndHeight
= newHeight
;
1522 this->GetEventHandler()->OnDrawOutline(dc
, pt
->sm_controlPointDragPosX
, pt
->sm_controlPointDragPosY
, newWidth
, newHeight
);
1526 void wxShape::OnSizingEndDragLeft(wxControlPoint
* pt
, double WXUNUSED(x
), double WXUNUSED(y
), int WXUNUSED(keys
), int WXUNUSED(attachment
))
1528 wxClientDC
dc(GetCanvas());
1529 GetCanvas()->PrepareDC(dc
);
1531 m_canvas
->ReleaseMouse();
1532 dc
.SetLogicalFunction(wxCOPY
);
1534 this->ResetControlPoints();
1538 if (!pt->m_eraseObject)
1542 this->SetSize(pt
->sm_controlPointDragEndWidth
, pt
->sm_controlPointDragEndHeight
);
1544 // The next operation could destroy this control point (it does for label objects,
1545 // via formatting the text), so save all values we're going to use, or
1546 // we'll be accessing garbage.
1547 wxShape
*theObject
= this;
1548 wxShapeCanvas
*theCanvas
= m_canvas
;
1549 bool eraseIt
= pt
->m_eraseObject
;
1551 if (theObject
->GetCentreResize())
1552 theObject
->Move(dc
, theObject
->GetX(), theObject
->GetY());
1554 theObject
->Move(dc
, pt
->sm_controlPointDragPosX
, pt
->sm_controlPointDragPosY
);
1558 theObject->Show(true);
1561 // Recursively redraw links if we have a composite.
1562 if (theObject
->GetChildren().GetCount() > 0)
1563 theObject
->DrawLinks(dc
, -1, true);
1565 double width
, height
;
1566 theObject
->GetBoundingBoxMax(&width
, &height
);
1567 theObject
->GetEventHandler()->OnEndSize(width
, height
);
1569 if (!theCanvas
->GetQuickEditMode() && eraseIt
) theCanvas
->Redraw(dc
);
1574 // Polygon control points
1576 IMPLEMENT_DYNAMIC_CLASS(wxPolygonControlPoint
, wxControlPoint
)
1578 wxPolygonControlPoint::wxPolygonControlPoint(wxShapeCanvas
*theCanvas
, wxShape
*object
, double size
,
1579 wxRealPoint
*vertex
, double the_xoffset
, double the_yoffset
):
1580 wxControlPoint(theCanvas
, object
, size
, the_xoffset
, the_yoffset
, 0)
1582 m_polygonVertex
= vertex
;
1583 m_originalDistance
= 0.0;
1586 wxPolygonControlPoint::~wxPolygonControlPoint()
1590 // Calculate what new size would be, at end of resize
1591 void wxPolygonControlPoint::CalculateNewSize(double x
, double y
)
1595 GetShape()->GetBoundingBoxMin(&bound_x
, &bound_y
);
1597 double dist
= (double)sqrt((x
- m_shape
->GetX())*(x
- m_shape
->GetX()) +
1598 (y
- m_shape
->GetY())*(y
- m_shape
->GetY()));
1600 m_newSize
.x
= (double)(dist
/this->m_originalDistance
)*this->m_originalSize
.x
;
1601 m_newSize
.y
= (double)(dist
/this->m_originalDistance
)*this->m_originalSize
.y
;
1605 // Implement resizing polygon or moving the vertex.
1606 void wxPolygonControlPoint::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
1608 m_shape
->GetEventHandler()->OnSizingDragLeft(this, draw
, x
, y
, keys
, attachment
);
1611 void wxPolygonControlPoint::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
1613 m_shape
->GetEventHandler()->OnSizingBeginDragLeft(this, x
, y
, keys
, attachment
);
1616 void wxPolygonControlPoint::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
1618 m_shape
->GetEventHandler()->OnSizingEndDragLeft(this, x
, y
, keys
, attachment
);
1621 // Control points ('handles') redirect control to the actual shape, to make it easier
1622 // to override sizing behaviour.
1623 void wxPolygonShape::OnSizingDragLeft(wxControlPoint
* pt
, bool WXUNUSED(draw
), double x
, double y
, int WXUNUSED(keys
), int WXUNUSED(attachment
))
1625 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
1627 wxClientDC
dc(GetCanvas());
1628 GetCanvas()->PrepareDC(dc
);
1630 dc
.SetLogicalFunction(OGLRBLF
);
1632 wxPen
dottedPen(*wxBLACK
, 1, wxDOT
);
1633 dc
.SetPen(dottedPen
);
1634 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1636 #if 0 // keys & KEY_CTRL)
1638 // TODO: mend this code. Currently we rely on altering the
1639 // actual points, but we should assume we're not, as per
1640 // the normal sizing case.
1641 m_canvas
->Snap(&x
, &y
);
1644 ppt
->m_polygonVertex
->x
= x
- this->GetX();
1645 ppt
->m_polygonVertex
->y
= y
- this->GetY();
1648 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1649 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1653 ppt
->CalculateNewSize(x
, y
);
1657 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1658 ppt
->GetNewSize().x
, ppt
->GetNewSize().y
);
1661 void wxPolygonShape::OnSizingBeginDragLeft(wxControlPoint
* pt
, double x
, double y
, int WXUNUSED(keys
), int WXUNUSED(attachment
))
1663 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
1665 wxClientDC
dc(GetCanvas());
1666 GetCanvas()->PrepareDC(dc
);
1670 dc
.SetLogicalFunction(OGLRBLF
);
1674 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1676 double dist
= (double)sqrt((x
- this->GetX())*(x
- this->GetX()) +
1677 (y
- this->GetY())*(y
- this->GetY()));
1678 ppt
->m_originalDistance
= dist
;
1679 ppt
->m_originalSize
.x
= bound_x
;
1680 ppt
->m_originalSize
.y
= bound_y
;
1682 if (ppt
->m_originalDistance
== 0.0) ppt
->m_originalDistance
= (double) 0.0001;
1684 wxPen
dottedPen(*wxBLACK
, 1, wxDOT
);
1685 dc
.SetPen(dottedPen
);
1686 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1688 #if 0 // keys & KEY_CTRL)
1690 // TODO: mend this code. Currently we rely on altering the
1691 // actual points, but we should assume we're not, as per
1692 // the normal sizing case.
1693 m_canvas
->Snap(&x
, &y
);
1696 ppt
->m_polygonVertex
->x
= x
- this->GetX();
1697 ppt
->m_polygonVertex
->y
= y
- this->GetY();
1700 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1701 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1705 ppt
->CalculateNewSize(x
, y
);
1709 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1710 ppt
->GetNewSize().x
, ppt
->GetNewSize().y
);
1712 m_canvas
->CaptureMouse();
1715 void wxPolygonShape::OnSizingEndDragLeft(wxControlPoint
* pt
, double WXUNUSED(x
), double WXUNUSED(y
), int keys
, int WXUNUSED(attachment
))
1717 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
1719 wxClientDC
dc(GetCanvas());
1720 GetCanvas()->PrepareDC(dc
);
1722 m_canvas
->ReleaseMouse();
1723 dc
.SetLogicalFunction(wxCOPY
);
1725 // If we're changing shape, must reset the original points
1726 if (keys
& KEY_CTRL
)
1728 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1729 ((wxPolygonShape
*)this)->UpdateOriginalPoints();
1733 SetSize(ppt
->GetNewSize().x
, ppt
->GetNewSize().y
);
1736 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1737 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1740 this->ResetControlPoints();
1741 this->Move(dc
, this->GetX(), this->GetY());
1742 if (!m_canvas
->GetQuickEditMode()) m_canvas
->Redraw(dc
);
1749 IMPLEMENT_DYNAMIC_CLASS(wxShapeRegion
, wxObject
)
1751 wxShapeRegion::wxShapeRegion()
1753 m_regionText
= wxEmptyString
;
1754 m_font
= g_oglNormalFont
;
1762 m_regionProportionX
= -1.0;
1763 m_regionProportionY
= -1.0;
1764 m_formatMode
= FORMAT_CENTRE_HORIZ
| FORMAT_CENTRE_VERT
;
1765 m_regionName
= wxEmptyString
;
1766 m_textColour
= wxT("BLACK");
1767 m_penColour
= wxT("BLACK");
1768 m_penStyle
= wxSOLID
;
1769 m_actualColourObject
= wxTheColourDatabase
->Find(wxT("BLACK"));
1770 m_actualPenObject
= NULL
;
1773 wxShapeRegion::wxShapeRegion(wxShapeRegion
& region
):wxObject()
1775 m_regionText
= region
.m_regionText
;
1776 m_regionName
= region
.m_regionName
;
1777 m_textColour
= region
.m_textColour
;
1779 m_font
= region
.m_font
;
1780 m_minHeight
= region
.m_minHeight
;
1781 m_minWidth
= region
.m_minWidth
;
1782 m_width
= region
.m_width
;
1783 m_height
= region
.m_height
;
1787 m_regionProportionX
= region
.m_regionProportionX
;
1788 m_regionProportionY
= region
.m_regionProportionY
;
1789 m_formatMode
= region
.m_formatMode
;
1790 m_actualColourObject
= region
.m_actualColourObject
;
1791 m_actualPenObject
= NULL
;
1792 m_penStyle
= region
.m_penStyle
;
1793 m_penColour
= region
.m_penColour
;
1796 wxObjectList::compatibility_iterator node
= region
.m_formattedText
.GetFirst();
1799 wxShapeTextLine
*line
= (wxShapeTextLine
*)node
->GetData();
1800 wxShapeTextLine
*new_line
=
1801 new wxShapeTextLine(line
->GetX(), line
->GetY(), line
->GetText());
1802 m_formattedText
.Append(new_line
);
1803 node
= node
->GetNext();
1807 wxShapeRegion::~wxShapeRegion()
1812 void wxShapeRegion::ClearText()
1814 wxObjectList::compatibility_iterator node
= m_formattedText
.GetFirst();
1817 wxShapeTextLine
*line
= (wxShapeTextLine
*)node
->GetData();
1818 wxObjectList::compatibility_iterator next
= node
->GetNext();
1820 m_formattedText
.Erase(node
);
1825 void wxShapeRegion::SetFont(wxFont
*f
)
1830 void wxShapeRegion::SetMinSize(double w
, double h
)
1836 void wxShapeRegion::SetSize(double w
, double h
)
1842 void wxShapeRegion::SetPosition(double xp
, double yp
)
1848 void wxShapeRegion::SetProportions(double xp
, double yp
)
1850 m_regionProportionX
= xp
;
1851 m_regionProportionY
= yp
;
1854 void wxShapeRegion::SetFormatMode(int mode
)
1856 m_formatMode
= mode
;
1859 void wxShapeRegion::SetColour(const wxString
& col
)
1862 m_actualColourObject
= col
;
1865 wxColour
wxShapeRegion::GetActualColourObject()
1867 m_actualColourObject
= wxTheColourDatabase
->Find(GetColour());
1868 return m_actualColourObject
;
1871 void wxShapeRegion::SetPenColour(const wxString
& col
)
1874 m_actualPenObject
= NULL
;
1877 // Returns NULL if the pen is invisible
1878 // (different to pen being transparent; indicates that
1879 // region boundary should not be drawn.)
1880 wxPen
*wxShapeRegion::GetActualPen()
1882 if (m_actualPenObject
)
1883 return m_actualPenObject
;
1885 if (!m_penColour
) return NULL
;
1886 if (m_penColour
== wxT("Invisible"))
1888 m_actualPenObject
= wxThePenList
->FindOrCreatePen(m_penColour
, 1, m_penStyle
);
1889 return m_actualPenObject
;