1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Basic OGL classes (2)
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
15 // For compilers that support precompilation, includes "wx.h".
16 #include <wx/wxprec.h>
27 #include <wx/wxexpr.h>
48 // Control point types
49 // Rectangle and most other shapes
50 #define CONTROL_POINT_VERTICAL 1
51 #define CONTROL_POINT_HORIZONTAL 2
52 #define CONTROL_POINT_DIAGONAL 3
55 #define CONTROL_POINT_ENDPOINT_TO 4
56 #define CONTROL_POINT_ENDPOINT_FROM 5
57 #define CONTROL_POINT_LINE 6
59 // Two stage construction: need to call Create
60 IMPLEMENT_DYNAMIC_CLASS(wxPolygonShape
, wxShape
)
62 wxPolygonShape::wxPolygonShape()
65 m_originalPoints
= NULL
;
68 void wxPolygonShape::Create(wxList
*the_points
)
72 m_originalPoints
= the_points
;
74 // Duplicate the list of points
75 m_points
= new wxList
;
77 wxNode
*node
= the_points
->First();
80 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
81 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
82 m_points
->Append((wxObject
*) new_point
);
85 CalculateBoundingBox();
86 m_originalWidth
= m_boundWidth
;
87 m_originalHeight
= m_boundHeight
;
88 SetDefaultRegionSize();
91 wxPolygonShape::~wxPolygonShape()
96 void wxPolygonShape::ClearPoints()
100 wxNode
*node
= m_points
->First();
103 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
106 node
= m_points
->First();
111 if (m_originalPoints
)
113 wxNode
*node
= m_originalPoints
->First();
116 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
119 node
= m_originalPoints
->First();
121 delete m_originalPoints
;
122 m_originalPoints
= NULL
;
127 // Width and height. Centre of object is centre of box.
128 void wxPolygonShape::GetBoundingBoxMin(double *width
, double *height
)
130 *width
= m_boundWidth
;
131 *height
= m_boundHeight
;
134 void wxPolygonShape::CalculateBoundingBox()
136 // Calculate bounding box at construction (and presumably resize) time
138 double right
= -10000;
140 double bottom
= -10000;
142 wxNode
*node
= m_points
->First();
145 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
146 if (point
->x
< left
) left
= point
->x
;
147 if (point
->x
> right
) right
= point
->x
;
149 if (point
->y
< top
) top
= point
->y
;
150 if (point
->y
> bottom
) bottom
= point
->y
;
154 m_boundWidth
= right
- left
;
155 m_boundHeight
= bottom
- top
;
158 // Recalculates the centre of the polygon, and
159 // readjusts the point offsets accordingly.
160 // Necessary since the centre of the polygon
161 // is expected to be the real centre of the bounding
163 void wxPolygonShape::CalculatePolygonCentre()
166 double right
= -10000;
168 double bottom
= -10000;
170 wxNode
*node
= m_points
->First();
173 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
174 if (point
->x
< left
) left
= point
->x
;
175 if (point
->x
> right
) right
= point
->x
;
177 if (point
->y
< top
) top
= point
->y
;
178 if (point
->y
> bottom
) bottom
= point
->y
;
182 double bwidth
= right
- left
;
183 double bheight
= bottom
- top
;
185 double newCentreX
= (double)(left
+ (bwidth
/2.0));
186 double newCentreY
= (double)(top
+ (bheight
/2.0));
188 node
= m_points
->First();
191 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
192 point
->x
-= newCentreX
;
193 point
->y
-= newCentreY
;
196 m_xpos
+= newCentreX
;
197 m_ypos
+= newCentreY
;
200 bool PolylineHitTest(double n
, double xvec
[], double yvec
[],
201 double x1
, double y1
, double x2
, double y2
)
205 double lastx
= xvec
[0];
206 double lasty
= yvec
[0];
208 double min_ratio
= 1.0;
213 for (i
= 1; i
< n
; i
++)
215 oglCheckLineIntersection(x1
, y1
, x2
, y2
, lastx
, lasty
, xvec
[i
], yvec
[i
],
216 &line_ratio
, &other_ratio
);
217 if (line_ratio
!= 1.0)
219 // sprintf(buf, "Line ratio = %.2f, other ratio = %.2f\n", line_ratio, other_ratio);
220 // ClipsErrorFunction(buf);
224 if (line_ratio
< min_ratio
)
225 min_ratio
= line_ratio
;
228 // Do last (implicit) line if last and first doubles are not identical
229 if (!(xvec
[0] == lastx
&& yvec
[0] == lasty
))
231 oglCheckLineIntersection(x1
, y1
, x2
, y2
, lastx
, lasty
, xvec
[0], yvec
[0],
232 &line_ratio
, &other_ratio
);
233 if (line_ratio
!= 1.0)
235 // sprintf(buf, "Line ratio = %.2f, other ratio = %.2f\n", line_ratio, other_ratio);
236 // ClipsErrorFunction(buf);
238 if (line_ratio
< min_ratio
)
239 min_ratio
= line_ratio
;
241 // ClipsErrorFunction("\n");
245 bool wxPolygonShape::HitTest(double x
, double y
, int *attachment
, double *distance
)
247 // Imagine four lines radiating from this point. If all of these lines hit the polygon,
248 // we're inside it, otherwise we're not. Obviously we'd need more radiating lines
249 // to be sure of correct results for very strange (concave) shapes.
250 double endPointsX
[4];
251 double endPointsY
[4];
254 endPointsY
[0] = (double)(y
- 1000.0);
256 endPointsX
[1] = (double)(x
+ 1000.0);
260 endPointsY
[2] = (double)(y
+ 1000.0);
262 endPointsX
[3] = (double)(x
- 1000.0);
265 // Store polygon points in an array
266 int np
= m_points
->Number();
267 double *xpoints
= new double[np
];
268 double *ypoints
= new double[np
];
269 wxNode
*node
= m_points
->First();
273 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
274 xpoints
[i
] = point
->x
+ m_xpos
;
275 ypoints
[i
] = point
->y
+ m_ypos
;
280 // We assume it's inside the polygon UNLESS one or more
281 // lines don't hit the outline.
282 bool isContained
= TRUE
;
285 for (i
= 0; i
< noPoints
; i
++)
287 if (!PolylineHitTest(np
, xpoints
, ypoints
, x
, y
, endPointsX
[i
], endPointsY
[i
]))
292 ClipsErrorFunction("It's a hit!\n");
294 ClipsErrorFunction("No hit.\n");
302 int nearest_attachment
= 0;
304 // If a hit, check the attachment points within the object.
305 int n
= GetNumberOfAttachments();
306 double nearest
= 999999.0;
308 for (i
= 0; i
< n
; i
++)
311 if (GetAttachmentPosition(i
, &xp
, &yp
))
313 double l
= (double)sqrt(((xp
- x
) * (xp
- x
)) +
314 ((yp
- y
) * (yp
- y
)));
318 nearest_attachment
= i
;
322 *attachment
= nearest_attachment
;
327 // Really need to be able to reset the shape! Otherwise, if the
328 // points ever go to zero, we've lost it, and can't resize.
329 void wxPolygonShape::SetSize(double new_width
, double new_height
, bool recursive
)
331 SetAttachmentSize(new_width
, new_height
);
333 // Multiply all points by proportion of new size to old size
334 double x_proportion
= (double)(fabs(new_width
/m_originalWidth
));
335 double y_proportion
= (double)(fabs(new_height
/m_originalHeight
));
337 wxNode
*node
= m_points
->First();
338 wxNode
*original_node
= m_originalPoints
->First();
339 while (node
&& original_node
)
341 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
342 wxRealPoint
*original_point
= (wxRealPoint
*)original_node
->Data();
344 point
->x
= (original_point
->x
* x_proportion
);
345 point
->y
= (original_point
->y
* y_proportion
);
348 original_node
= original_node
->Next();
351 // CalculateBoundingBox();
352 m_boundWidth
= (double)fabs(new_width
);
353 m_boundHeight
= (double)fabs(new_height
);
354 SetDefaultRegionSize();
357 // Make the original points the same as the working points
358 void wxPolygonShape::UpdateOriginalPoints()
360 if (!m_originalPoints
) m_originalPoints
= new wxList
;
361 wxNode
*original_node
= m_originalPoints
->First();
362 while (original_node
)
364 wxNode
*next_node
= original_node
->Next();
365 wxRealPoint
*original_point
= (wxRealPoint
*)original_node
->Data();
366 delete original_point
;
367 delete original_node
;
369 original_node
= next_node
;
372 wxNode
*node
= m_points
->First();
375 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
376 wxRealPoint
*original_point
= new wxRealPoint(point
->x
, point
->y
);
377 m_originalPoints
->Append((wxObject
*) original_point
);
381 CalculateBoundingBox();
382 m_originalWidth
= m_boundWidth
;
383 m_originalHeight
= m_boundHeight
;
386 void wxPolygonShape::AddPolygonPoint(int pos
)
388 wxNode
*node
= m_points
->Nth(pos
);
389 if (!node
) node
= m_points
->First();
390 wxRealPoint
*firstPoint
= (wxRealPoint
*)node
->Data();
392 wxNode
*node2
= m_points
->Nth(pos
+ 1);
393 if (!node2
) node2
= m_points
->First();
394 wxRealPoint
*secondPoint
= (wxRealPoint
*)node2
->Data();
396 double x
= (double)((secondPoint
->x
- firstPoint
->x
)/2.0 + firstPoint
->x
);
397 double y
= (double)((secondPoint
->y
- firstPoint
->y
)/2.0 + firstPoint
->y
);
398 wxRealPoint
*point
= new wxRealPoint(x
, y
);
400 if (pos
>= (m_points
->Number() - 1))
401 m_points
->Append((wxObject
*) point
);
403 m_points
->Insert(node2
, (wxObject
*) point
);
405 UpdateOriginalPoints();
409 DeleteControlPoints();
414 void wxPolygonShape::DeletePolygonPoint(int pos
)
416 wxNode
*node
= m_points
->Nth(pos
);
419 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
422 UpdateOriginalPoints();
425 DeleteControlPoints();
431 // Assume (x1, y1) is centre of box (most generally, line end at box)
432 bool wxPolygonShape::GetPerimeterPoint(double x1
, double y1
,
433 double x2
, double y2
,
434 double *x3
, double *y3
)
436 int n
= m_points
->Number();
438 // First check for situation where the line is vertical,
439 // and we would want to connect to a point on that vertical --
440 // oglFindEndForPolyline can't cope with this (the arrow
441 // gets drawn to the wrong place).
442 if ((!m_attachmentMode
) && (x1
== x2
))
444 // Look for the point we'd be connecting to. This is
446 wxNode
*node
= m_points
->First();
449 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
452 if ((y2
> y1
) && (point
->y
> 0.0))
454 *x3
= point
->x
+ m_xpos
;
455 *y3
= point
->y
+ m_ypos
;
458 else if ((y2
< y1
) && (point
->y
< 0.0))
460 *x3
= point
->x
+ m_xpos
;
461 *y3
= point
->y
+ m_ypos
;
469 double *xpoints
= new double[n
];
470 double *ypoints
= new double[n
];
472 wxNode
*node
= m_points
->First();
476 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
477 xpoints
[i
] = point
->x
+ m_xpos
;
478 ypoints
[i
] = point
->y
+ m_ypos
;
483 oglFindEndForPolyline(n
, xpoints
, ypoints
,
484 x1
, y1
, x2
, y2
, x3
, y3
);
492 void wxPolygonShape::OnDraw(wxDC
& dc
)
494 int n
= m_points
->Number();
495 wxPoint
*intPoints
= new wxPoint
[n
];
497 for (i
= 0; i
< n
; i
++)
499 wxRealPoint
* point
= (wxRealPoint
*) m_points
->Nth(i
)->Data();
500 intPoints
[i
].x
= WXROUND(point
->x
);
501 intPoints
[i
].y
= WXROUND(point
->y
);
504 if (m_shadowMode
!= SHADOW_NONE
)
507 dc
.SetBrush(m_shadowBrush
);
508 dc
.SetPen(g_oglTransparentPen
);
510 dc
.DrawPolygon(n
, intPoints
, WXROUND(m_xpos
+ m_shadowOffsetX
), WXROUND(m_ypos
+ m_shadowOffsetY
));
515 if (m_pen
->GetWidth() == 0)
516 dc
.SetPen(g_oglTransparentPen
);
521 dc
.SetBrush(m_brush
);
522 dc
.DrawPolygon(n
, intPoints
, WXROUND(m_xpos
), WXROUND(m_ypos
));
527 void wxPolygonShape::OnDrawOutline(wxDC
& dc
, double x
, double y
, double w
, double h
)
529 dc
.SetBrush(wxTRANSPARENT_BRUSH
);
530 // Multiply all points by proportion of new size to old size
531 double x_proportion
= (double)(fabs(w
/m_originalWidth
));
532 double y_proportion
= (double)(fabs(h
/m_originalHeight
));
534 int n
= m_originalPoints
->Number();
535 wxPoint
*intPoints
= new wxPoint
[n
];
537 for (i
= 0; i
< n
; i
++)
539 wxRealPoint
* point
= (wxRealPoint
*) m_originalPoints
->Nth(i
)->Data();
540 intPoints
[i
].x
= WXROUND(x_proportion
* point
->x
);
541 intPoints
[i
].y
= WXROUND(y_proportion
* point
->y
);
543 dc
.DrawPolygon(n
, intPoints
, WXROUND(x
), WXROUND(y
));
547 // Make as many control points as there are vertices.
548 void wxPolygonShape::MakeControlPoints()
550 wxNode
*node
= m_points
->First();
553 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
554 wxPolygonControlPoint
*control
= new wxPolygonControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
,
555 point
, point
->x
, point
->y
);
556 m_canvas
->AddShape(control
);
557 m_controlPoints
.Append(control
);
562 void wxPolygonShape::ResetControlPoints()
564 wxNode
*node
= m_points
->First();
565 wxNode
*controlPointNode
= m_controlPoints
.First();
566 while (node
&& controlPointNode
)
568 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
569 wxPolygonControlPoint
*controlPoint
= (wxPolygonControlPoint
*)controlPointNode
->Data();
571 controlPoint
->m_xoffset
= point
->x
;
572 controlPoint
->m_yoffset
= point
->y
;
573 controlPoint
->m_polygonVertex
= point
;
576 controlPointNode
= controlPointNode
->Next();
582 void wxPolygonShape::WriteAttributes(wxExpr
*clause
)
584 wxShape::WriteAttributes(clause
);
586 clause
->AddAttributeValue("x", m_xpos
);
587 clause
->AddAttributeValue("y", m_ypos
);
589 // Make a list of lists for the coordinates
590 wxExpr
*list
= new wxExpr(wxExprList
);
591 wxNode
*node
= m_points
->First();
594 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
595 wxExpr
*point_list
= new wxExpr(wxExprList
);
596 wxExpr
*x_expr
= new wxExpr((double)point
->x
);
597 wxExpr
*y_expr
= new wxExpr((double)point
->y
);
599 point_list
->Append(x_expr
);
600 point_list
->Append(y_expr
);
601 list
->Append(point_list
);
605 clause
->AddAttributeValue("points", list
);
607 // Save the original (unscaled) points
608 list
= new wxExpr(wxExprList
);
609 node
= m_originalPoints
->First();
612 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
613 wxExpr
*point_list
= new wxExpr(wxExprList
);
614 wxExpr
*x_expr
= new wxExpr((double) point
->x
);
615 wxExpr
*y_expr
= new wxExpr((double) point
->y
);
616 point_list
->Append(x_expr
);
617 point_list
->Append(y_expr
);
618 list
->Append(point_list
);
622 clause
->AddAttributeValue("m_originalPoints", list
);
625 void wxPolygonShape::ReadAttributes(wxExpr
*clause
)
627 wxShape::ReadAttributes(clause
);
629 // Read a list of lists
630 m_points
= new wxList
;
631 m_originalPoints
= new wxList
;
633 wxExpr
*points_list
= NULL
;
634 clause
->AssignAttributeValue("points", &points_list
);
636 // If no points_list, don't crash!! Assume a diamond instead.
637 double the_height
= 100.0;
638 double the_width
= 100.0;
641 wxRealPoint
*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
);
650 point
= new wxRealPoint((-the_width
/2), 0.0);
651 m_points
->Append((wxObject
*) point
);
653 point
= new wxRealPoint(0.0, (-the_height
/2));
654 m_points
->Append((wxObject
*) point
);
658 wxExpr
*node
= points_list
->value
.first
;
662 wxExpr
*xexpr
= node
->value
.first
;
663 long x
= xexpr
->IntegerValue();
665 wxExpr
*yexpr
= xexpr
->next
;
666 long y
= yexpr
->IntegerValue();
668 wxRealPoint
*point
= new wxRealPoint((double)x
, (double)y
);
669 m_points
->Append((wxObject
*) point
);
676 clause
->AssignAttributeValue("m_originalPoints", &points_list
);
678 // If no points_list, don't crash!! Assume a diamond instead.
681 wxRealPoint
*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 point
= new wxRealPoint((-the_width
/2), 0.0);
691 m_originalPoints
->Append((wxObject
*) point
);
693 point
= new wxRealPoint(0.0, (-the_height
/2));
694 m_originalPoints
->Append((wxObject
*) point
);
696 m_originalWidth
= the_width
;
697 m_originalHeight
= the_height
;
701 wxExpr
*node
= points_list
->value
.first
;
704 double max_x
= -1000;
705 double max_y
= -1000;
708 wxExpr
*xexpr
= node
->value
.first
;
709 long x
= xexpr
->IntegerValue();
711 wxExpr
*yexpr
= xexpr
->next
;
712 long y
= yexpr
->IntegerValue();
714 wxRealPoint
*point
= new wxRealPoint((double)x
, (double)y
);
715 m_originalPoints
->Append((wxObject
*) point
);
728 m_originalWidth
= max_x
- min_x
;
729 m_originalHeight
= max_y
- min_y
;
732 CalculateBoundingBox();
736 void wxPolygonShape::Copy(wxShape
& copy
)
740 wxASSERT( copy
.IsKindOf(CLASSINFO(wxPolygonShape
)) );
742 wxPolygonShape
& polyCopy
= (wxPolygonShape
&) copy
;
744 polyCopy
.ClearPoints();
746 polyCopy
.m_points
= new wxList
;
747 polyCopy
.m_originalPoints
= new wxList
;
749 wxNode
*node
= m_points
->First();
752 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
753 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
754 polyCopy
.m_points
->Append((wxObject
*) new_point
);
757 node
= m_originalPoints
->First();
760 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
761 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
762 polyCopy
.m_originalPoints
->Append((wxObject
*) new_point
);
765 polyCopy
.m_boundWidth
= m_boundWidth
;
766 polyCopy
.m_boundHeight
= m_boundHeight
;
767 polyCopy
.m_originalWidth
= m_originalWidth
;
768 polyCopy
.m_originalHeight
= m_originalHeight
;
771 int wxPolygonShape::GetNumberOfAttachments() const
773 int maxN
= (m_points
? (m_points
->Number() - 1) : 0);
774 wxNode
*node
= m_attachmentPoints
.First();
777 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
778 if (point
->m_id
> maxN
)
785 bool wxPolygonShape::GetAttachmentPosition(int attachment
, double *x
, double *y
,
786 int nth
, int no_arcs
, wxLineShape
*line
)
788 if (m_attachmentMode
&& m_points
&& attachment
< m_points
->Number())
790 wxRealPoint
*point
= (wxRealPoint
*)m_points
->Nth(attachment
)->Data();
791 *x
= point
->x
+ m_xpos
;
792 *y
= point
->y
+ m_ypos
;
796 { return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
); }
799 bool wxPolygonShape::AttachmentIsValid(int attachment
)
804 if ((attachment
>= 0) && (attachment
< m_points
->Number()))
807 wxNode
*node
= m_attachmentPoints
.First();
810 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
811 if (point
->m_id
== attachment
)
818 // Rotate about the given axis by the given amount in radians
819 void wxPolygonShape::Rotate(double x
, double y
, double theta
)
821 double actualTheta
= theta
-m_rotation
;
823 // Rotate attachment points
824 double sinTheta
= (double)sin(actualTheta
);
825 double cosTheta
= (double)cos(actualTheta
);
826 wxNode
*node
= m_attachmentPoints
.First();
829 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
830 double x1
= point
->m_x
;
831 double y1
= point
->m_y
;
832 point
->m_x
= x1
*cosTheta
- y1
*sinTheta
+ x
*(1.0 - cosTheta
) + y
*sinTheta
;
833 point
->m_y
= x1
*sinTheta
+ y1
*cosTheta
+ y
*(1.0 - cosTheta
) + x
*sinTheta
;
837 node
= m_points
->First();
840 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
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
;
847 node
= m_originalPoints
->First();
850 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
851 double x1
= point
->x
;
852 double y1
= point
->y
;
853 point
->x
= x1
*cosTheta
- y1
*sinTheta
+ x
*(1.0 - cosTheta
) + y
*sinTheta
;
854 point
->y
= x1
*sinTheta
+ y1
*cosTheta
+ y
*(1.0 - cosTheta
) + x
*sinTheta
;
860 CalculatePolygonCentre();
861 CalculateBoundingBox();
862 ResetControlPoints();
867 IMPLEMENT_DYNAMIC_CLASS(wxRectangleShape
, wxShape
)
869 wxRectangleShape::wxRectangleShape(double w
, double h
)
871 m_width
= w
; m_height
= h
; m_cornerRadius
= 0.0;
872 SetDefaultRegionSize();
875 void wxRectangleShape::OnDraw(wxDC
& dc
)
877 double x1
= (double)(m_xpos
- m_width
/2.0);
878 double y1
= (double)(m_ypos
- m_height
/2.0);
880 if (m_shadowMode
!= SHADOW_NONE
)
883 dc
.SetBrush(m_shadowBrush
);
884 dc
.SetPen(g_oglTransparentPen
);
886 if (m_cornerRadius
!= 0.0)
887 dc
.DrawRoundedRectangle(WXROUND(x1
+ m_shadowOffsetX
), WXROUND(y1
+ m_shadowOffsetY
),
888 WXROUND(m_width
), WXROUND(m_height
), m_cornerRadius
);
890 dc
.DrawRectangle(WXROUND(x1
+ m_shadowOffsetX
), WXROUND(y1
+ m_shadowOffsetY
), WXROUND(m_width
), WXROUND(m_height
));
895 if (m_pen
->GetWidth() == 0)
896 dc
.SetPen(g_oglTransparentPen
);
901 dc
.SetBrush(m_brush
);
903 if (m_cornerRadius
!= 0.0)
904 dc
.DrawRoundedRectangle(WXROUND(x1
), WXROUND(y1
), WXROUND(m_width
), WXROUND(m_height
), m_cornerRadius
);
906 dc
.DrawRectangle(WXROUND(x1
), WXROUND(y1
), WXROUND(m_width
), WXROUND(m_height
));
909 void wxRectangleShape::GetBoundingBoxMin(double *the_width
, double *the_height
)
911 *the_width
= m_width
;
912 *the_height
= m_height
;
915 void wxRectangleShape::SetSize(double x
, double y
, bool recursive
)
917 SetAttachmentSize(x
, y
);
918 m_width
= (double)wxMax(x
, 1.0);
919 m_height
= (double)wxMax(y
, 1.0);
920 SetDefaultRegionSize();
923 void wxRectangleShape::SetCornerRadius(double rad
)
925 m_cornerRadius
= rad
;
928 // Assume (x1, y1) is centre of box (most generally, line end at box)
929 bool wxRectangleShape::GetPerimeterPoint(double x1
, double y1
,
930 double x2
, double y2
,
931 double *x3
, double *y3
)
933 double bound_x
, bound_y
;
934 GetBoundingBoxMax(&bound_x
, &bound_y
);
935 oglFindEndForBox(bound_x
, bound_y
, m_xpos
, m_ypos
, x2
, y2
, x3
, y3
);
941 void wxRectangleShape::WriteAttributes(wxExpr
*clause
)
943 wxShape::WriteAttributes(clause
);
944 clause
->AddAttributeValue("x", m_xpos
);
945 clause
->AddAttributeValue("y", m_ypos
);
947 clause
->AddAttributeValue("width", m_width
);
948 clause
->AddAttributeValue("height", m_height
);
949 if (m_cornerRadius
!= 0.0)
950 clause
->AddAttributeValue("corner", m_cornerRadius
);
953 void wxRectangleShape::ReadAttributes(wxExpr
*clause
)
955 wxShape::ReadAttributes(clause
);
956 clause
->AssignAttributeValue("width", &m_width
);
957 clause
->AssignAttributeValue("height", &m_height
);
958 clause
->AssignAttributeValue("corner", &m_cornerRadius
);
960 // In case we're reading an old file, set the region's size
961 if (m_regions
.Number() == 1)
963 wxShapeRegion
*region
= (wxShapeRegion
*)m_regions
.First()->Data();
964 region
->SetSize(m_width
, m_height
);
969 void wxRectangleShape::Copy(wxShape
& copy
)
973 wxASSERT( copy
.IsKindOf(CLASSINFO(wxRectangleShape
)) );
975 wxRectangleShape
& rectCopy
= (wxRectangleShape
&) copy
;
976 rectCopy
.m_width
= m_width
;
977 rectCopy
.m_height
= m_height
;
978 rectCopy
.m_cornerRadius
= m_cornerRadius
;
981 int wxRectangleShape::GetNumberOfAttachments() const
983 return wxShape::GetNumberOfAttachments();
987 // There are 4 attachment points on a rectangle - 0 = top, 1 = right, 2 = bottom,
989 bool wxRectangleShape::GetAttachmentPosition(int attachment
, double *x
, double *y
,
990 int nth
, int no_arcs
, wxLineShape
*line
)
992 if (m_attachmentMode
)
994 double top
= (double)(m_ypos
+ m_height
/2.0);
995 double bottom
= (double)(m_ypos
- m_height
/2.0);
996 double left
= (double)(m_xpos
- m_width
/2.0);
997 double right
= (double)(m_xpos
+ m_width
/2.0);
999 bool isEnd
= (line
&& line
->IsEnd(this));
1006 wxRealPoint pt
= CalcSimpleAttachment(wxRealPoint(left
, bottom
), wxRealPoint(right
, bottom
),
1007 nth
, no_arcs
, line
);
1009 *x
= pt
.x
; *y
= pt
.y
;
1014 wxRealPoint pt
= CalcSimpleAttachment(wxRealPoint(right
, bottom
), wxRealPoint(right
, top
),
1015 nth
, no_arcs
, line
);
1017 *x
= pt
.x
; *y
= pt
.y
;
1022 wxRealPoint pt
= CalcSimpleAttachment(wxRealPoint(left
, top
), wxRealPoint(right
, top
),
1023 nth
, no_arcs
, line
);
1025 *x
= pt
.x
; *y
= pt
.y
;
1030 wxRealPoint pt
= CalcSimpleAttachment(wxRealPoint(left
, bottom
), wxRealPoint(left
, top
),
1031 nth
, no_arcs
, line
);
1033 *x
= pt
.x
; *y
= pt
.y
;
1038 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
1046 { *x
= m_xpos
; *y
= m_ypos
; return TRUE
; }
1049 // Text object (no box)
1051 IMPLEMENT_DYNAMIC_CLASS(wxTextShape
, wxRectangleShape
)
1053 wxTextShape::wxTextShape(double width
, double height
):
1054 wxRectangleShape(width
, height
)
1058 void wxTextShape::OnDraw(wxDC
& dc
)
1062 void wxTextShape::Copy(wxShape
& copy
)
1064 wxRectangleShape::Copy(copy
);
1068 void wxTextShape::WriteAttributes(wxExpr
*clause
)
1070 wxRectangleShape::WriteAttributes(clause
);
1076 IMPLEMENT_DYNAMIC_CLASS(wxEllipseShape
, wxShape
)
1078 wxEllipseShape::wxEllipseShape(double w
, double h
)
1080 m_width
= w
; m_height
= h
;
1081 SetDefaultRegionSize();
1084 void wxEllipseShape::GetBoundingBoxMin(double *w
, double *h
)
1086 *w
= m_width
; *h
= m_height
;
1089 bool wxEllipseShape::GetPerimeterPoint(double x1
, double y1
,
1090 double x2
, double y2
,
1091 double *x3
, double *y3
)
1093 double bound_x
, bound_y
;
1094 GetBoundingBoxMax(&bound_x
, &bound_y
);
1096 // oglFindEndForBox(bound_x, bound_y, m_xpos, m_ypos, x2, y2, x3, y3);
1097 oglDrawArcToEllipse(m_xpos
, m_ypos
, bound_x
, bound_y
, x2
, y2
, x1
, y1
, x3
, y3
);
1102 void wxEllipseShape::OnDraw(wxDC
& dc
)
1104 if (m_shadowMode
!= SHADOW_NONE
)
1107 dc
.SetBrush(m_shadowBrush
);
1108 dc
.SetPen(g_oglTransparentPen
);
1109 dc
.DrawEllipse((m_xpos
- GetWidth()/2) + m_shadowOffsetX
,
1110 (m_ypos
- GetHeight()/2) + m_shadowOffsetY
,
1111 GetWidth(), GetHeight());
1116 if (m_pen
->GetWidth() == 0)
1117 dc
.SetPen(g_oglTransparentPen
);
1122 dc
.SetBrush(m_brush
);
1123 dc
.DrawEllipse((m_xpos
- GetWidth()/2), (m_ypos
- GetHeight()/2), GetWidth(), GetHeight());
1126 void wxEllipseShape::SetSize(double x
, double y
, bool recursive
)
1128 SetAttachmentSize(x
, y
);
1131 SetDefaultRegionSize();
1135 void wxEllipseShape::WriteAttributes(wxExpr
*clause
)
1137 wxShape::WriteAttributes(clause
);
1138 clause
->AddAttributeValue("x", m_xpos
);
1139 clause
->AddAttributeValue("y", m_ypos
);
1141 clause
->AddAttributeValue("width", m_width
);
1142 clause
->AddAttributeValue("height", m_height
);
1145 void wxEllipseShape::ReadAttributes(wxExpr
*clause
)
1147 wxShape::ReadAttributes(clause
);
1148 clause
->AssignAttributeValue("width", &m_width
);
1149 clause
->AssignAttributeValue("height", &m_height
);
1151 // In case we're reading an old file, set the region's size
1152 if (m_regions
.Number() == 1)
1154 wxShapeRegion
*region
= (wxShapeRegion
*)m_regions
.First()->Data();
1155 region
->SetSize(m_width
, m_height
);
1160 void wxEllipseShape::Copy(wxShape
& copy
)
1162 wxShape::Copy(copy
);
1164 wxASSERT( copy
.IsKindOf(CLASSINFO(wxEllipseShape
)) );
1166 wxEllipseShape
& ellipseCopy
= (wxEllipseShape
&) copy
;
1168 ellipseCopy
.m_width
= m_width
;
1169 ellipseCopy
.m_height
= m_height
;
1172 int wxEllipseShape::GetNumberOfAttachments() const
1174 return wxShape::GetNumberOfAttachments();
1177 // There are 4 attachment points on an ellipse - 0 = top, 1 = right, 2 = bottom,
1179 bool wxEllipseShape::GetAttachmentPosition(int attachment
, double *x
, double *y
,
1180 int nth
, int no_arcs
, wxLineShape
*line
)
1182 if (m_attachmentMode
)
1184 double top
= (double)(m_ypos
+ m_height
/2.0);
1185 double bottom
= (double)(m_ypos
- m_height
/2.0);
1186 double left
= (double)(m_xpos
- m_width
/2.0);
1187 double right
= (double)(m_xpos
+ m_width
/2.0);
1192 if (m_spaceAttachments
)
1193 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
1196 // We now have the point on the bounding box: but get the point on the ellipse
1197 // by imagining a vertical line from (*x, m_ypos - m_height- 500) to (*x, m_ypos) intersecting
1199 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, *x
, (double)(m_ypos
-m_height
-500), *x
, m_ypos
, x
, y
);
1205 if (m_spaceAttachments
)
1206 *y
= bottom
+ (nth
+ 1)*m_height
/(no_arcs
+ 1);
1208 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, (double)(m_xpos
+m_width
+500), *y
, m_xpos
, *y
, x
, y
);
1213 if (m_spaceAttachments
)
1214 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
1217 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, *x
, (double)(m_ypos
+m_height
+500), *x
, m_ypos
, x
, y
);
1223 if (m_spaceAttachments
)
1224 *y
= bottom
+ (nth
+ 1)*m_height
/(no_arcs
+ 1);
1226 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, (double)(m_xpos
-m_width
-500), *y
, m_xpos
, *y
, x
, y
);
1231 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
1238 { *x
= m_xpos
; *y
= m_ypos
; return TRUE
; }
1243 IMPLEMENT_DYNAMIC_CLASS(wxCircleShape
, wxEllipseShape
)
1245 wxCircleShape::wxCircleShape(double diameter
):wxEllipseShape(diameter
, diameter
)
1247 SetMaintainAspectRatio(TRUE
);
1250 void wxCircleShape::Copy(wxShape
& copy
)
1252 wxEllipseShape::Copy(copy
);
1255 bool wxCircleShape::GetPerimeterPoint(double x1
, double y1
,
1256 double x2
, double y2
,
1257 double *x3
, double *y3
)
1259 oglFindEndForCircle(m_width
/2,
1260 m_xpos
, m_ypos
, // Centre of circle
1261 x2
, y2
, // Other end of line
1269 double wxControlPoint::sm_controlPointDragStartX
= 0.0;
1270 double wxControlPoint::sm_controlPointDragStartY
= 0.0;
1271 double wxControlPoint::sm_controlPointDragStartWidth
= 0.0;
1272 double wxControlPoint::sm_controlPointDragStartHeight
= 0.0;
1273 double wxControlPoint::sm_controlPointDragEndWidth
= 0.0;
1274 double wxControlPoint::sm_controlPointDragEndHeight
= 0.0;
1275 double wxControlPoint::sm_controlPointDragPosX
= 0.0;
1276 double wxControlPoint::sm_controlPointDragPosY
= 0.0;
1278 IMPLEMENT_DYNAMIC_CLASS(wxControlPoint
, wxRectangleShape
)
1280 wxControlPoint::wxControlPoint(wxShapeCanvas
*theCanvas
, wxShape
*object
, double size
, double the_xoffset
, double the_yoffset
, int the_type
):wxRectangleShape(size
, size
)
1282 m_canvas
= theCanvas
;
1284 m_xoffset
= the_xoffset
;
1285 m_yoffset
= the_yoffset
;
1287 SetPen(g_oglBlackForegroundPen
);
1288 SetBrush(wxBLACK_BRUSH
);
1291 m_eraseObject
= TRUE
;
1294 wxControlPoint::~wxControlPoint()
1298 // Don't even attempt to draw any text - waste of time!
1299 void wxControlPoint::OnDrawContents(wxDC
& dc
)
1303 void wxControlPoint::OnDraw(wxDC
& dc
)
1305 m_xpos
= m_shape
->GetX() + m_xoffset
;
1306 m_ypos
= m_shape
->GetY() + m_yoffset
;
1307 wxRectangleShape::OnDraw(dc
);
1310 void wxControlPoint::OnErase(wxDC
& dc
)
1312 wxRectangleShape::OnErase(dc
);
1315 // Implement resizing of canvas object
1316 void wxControlPoint::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
1318 m_shape
->GetEventHandler()->OnSizingDragLeft(this, draw
, x
, y
, keys
, attachment
);
1321 void wxControlPoint::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
1323 m_shape
->GetEventHandler()->OnSizingBeginDragLeft(this, x
, y
, keys
, attachment
);
1326 void wxControlPoint::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
1328 m_shape
->GetEventHandler()->OnSizingEndDragLeft(this, x
, y
, keys
, attachment
);
1331 int wxControlPoint::GetNumberOfAttachments() const
1336 bool wxControlPoint::GetAttachmentPosition(int attachment
, double *x
, double *y
,
1337 int nth
, int no_arcs
, wxLineShape
*line
)
1339 *x
= m_xpos
; *y
= m_ypos
;
1343 // Control points ('handles') redirect control to the actual shape, to make it easier
1344 // to override sizing behaviour.
1345 void wxShape::OnSizingDragLeft(wxControlPoint
* pt
, bool draw
, double x
, double y
, int keys
, int attachment
)
1349 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1351 wxClientDC
dc(GetCanvas());
1352 GetCanvas()->PrepareDC(dc
);
1354 dc
.SetLogicalFunction(wxXOR
);
1356 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1357 dc
.SetPen(dottedPen
);
1358 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1360 if (this->GetCentreResize())
1362 // Maintain the same centre point.
1363 double new_width
= (double)(2.0*fabs(x
- this->GetX()));
1364 double new_height
= (double)(2.0*fabs(y
- this->GetY()));
1366 // Constrain sizing according to what control point you're dragging
1367 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1369 if (GetMaintainAspectRatio())
1371 new_height
= bound_y
*(new_width
/bound_x
);
1374 new_height
= bound_y
;
1376 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1378 if (GetMaintainAspectRatio())
1380 new_width
= bound_x
*(new_height
/bound_y
);
1383 new_width
= bound_x
;
1385 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& (keys
& KEY_SHIFT
))
1386 new_height
= bound_y
*(new_width
/bound_x
);
1388 if (this->GetFixedWidth())
1389 new_width
= bound_x
;
1391 if (this->GetFixedHeight())
1392 new_height
= bound_y
;
1394 pt
->sm_controlPointDragEndWidth
= new_width
;
1395 pt
->sm_controlPointDragEndHeight
= new_height
;
1397 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1398 new_width
, new_height
);
1402 // Don't maintain the same centre point!
1403 double newX1
= wxMin(pt
->sm_controlPointDragStartX
, x
);
1404 double newY1
= wxMin(pt
->sm_controlPointDragStartY
, y
);
1405 double newX2
= wxMax(pt
->sm_controlPointDragStartX
, x
);
1406 double newY2
= wxMax(pt
->sm_controlPointDragStartY
, y
);
1407 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1409 newY1
= pt
->sm_controlPointDragStartY
;
1410 newY2
= newY1
+ pt
->sm_controlPointDragStartHeight
;
1412 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1414 newX1
= pt
->sm_controlPointDragStartX
;
1415 newX2
= newX1
+ pt
->sm_controlPointDragStartWidth
;
1417 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& ((keys
& KEY_SHIFT
) || GetMaintainAspectRatio()))
1419 double newH
= (double)((newX2
- newX1
)*(pt
->sm_controlPointDragStartHeight
/pt
->sm_controlPointDragStartWidth
));
1420 if (GetY() > pt
->sm_controlPointDragStartY
)
1421 newY2
= (double)(newY1
+ newH
);
1423 newY1
= (double)(newY2
- newH
);
1425 double newWidth
= (double)(newX2
- newX1
);
1426 double newHeight
= (double)(newY2
- newY1
);
1428 if (pt
->m_type
== CONTROL_POINT_VERTICAL
&& GetMaintainAspectRatio())
1430 newWidth
= bound_x
* (newHeight
/bound_y
) ;
1433 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
&& GetMaintainAspectRatio())
1435 newHeight
= bound_y
* (newWidth
/bound_x
) ;
1438 pt
->sm_controlPointDragPosX
= (double)(newX1
+ (newWidth
/2.0));
1439 pt
->sm_controlPointDragPosY
= (double)(newY1
+ (newHeight
/2.0));
1440 if (this->GetFixedWidth())
1443 if (this->GetFixedHeight())
1444 newHeight
= bound_y
;
1446 pt
->sm_controlPointDragEndWidth
= newWidth
;
1447 pt
->sm_controlPointDragEndHeight
= newHeight
;
1448 this->GetEventHandler()->OnDrawOutline(dc
, pt
->sm_controlPointDragPosX
, pt
->sm_controlPointDragPosY
, newWidth
, newHeight
);
1452 void wxShape::OnSizingBeginDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int attachment
)
1454 m_canvas
->CaptureMouse();
1456 wxClientDC
dc(GetCanvas());
1457 GetCanvas()->PrepareDC(dc
);
1459 if (pt->m_eraseObject)
1463 dc
.SetLogicalFunction(wxXOR
);
1467 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1469 // Choose the 'opposite corner' of the object as the stationary
1470 // point in case this is non-centring resizing.
1471 if (pt
->GetX() < this->GetX())
1472 pt
->sm_controlPointDragStartX
= (double)(this->GetX() + (bound_x
/2.0));
1474 pt
->sm_controlPointDragStartX
= (double)(this->GetX() - (bound_x
/2.0));
1476 if (pt
->GetY() < this->GetY())
1477 pt
->sm_controlPointDragStartY
= (double)(this->GetY() + (bound_y
/2.0));
1479 pt
->sm_controlPointDragStartY
= (double)(this->GetY() - (bound_y
/2.0));
1481 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1482 pt
->sm_controlPointDragStartY
= (double)(this->GetY() - (bound_y
/2.0));
1483 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1484 pt
->sm_controlPointDragStartX
= (double)(this->GetX() - (bound_x
/2.0));
1486 // We may require the old width and height.
1487 pt
->sm_controlPointDragStartWidth
= bound_x
;
1488 pt
->sm_controlPointDragStartHeight
= bound_y
;
1490 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1491 dc
.SetPen(dottedPen
);
1492 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1494 if (this->GetCentreResize())
1496 double new_width
= (double)(2.0*fabs(x
- this->GetX()));
1497 double new_height
= (double)(2.0*fabs(y
- this->GetY()));
1499 // Constrain sizing according to what control point you're dragging
1500 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1502 if (GetMaintainAspectRatio())
1504 new_height
= bound_y
*(new_width
/bound_x
);
1507 new_height
= bound_y
;
1509 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1511 if (GetMaintainAspectRatio())
1513 new_width
= bound_x
*(new_height
/bound_y
);
1516 new_width
= bound_x
;
1518 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& (keys
& KEY_SHIFT
))
1519 new_height
= bound_y
*(new_width
/bound_x
);
1521 if (this->GetFixedWidth())
1522 new_width
= bound_x
;
1524 if (this->GetFixedHeight())
1525 new_height
= bound_y
;
1527 pt
->sm_controlPointDragEndWidth
= new_width
;
1528 pt
->sm_controlPointDragEndHeight
= new_height
;
1529 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1530 new_width
, new_height
);
1534 // Don't maintain the same centre point!
1535 double newX1
= wxMin(pt
->sm_controlPointDragStartX
, x
);
1536 double newY1
= wxMin(pt
->sm_controlPointDragStartY
, y
);
1537 double newX2
= wxMax(pt
->sm_controlPointDragStartX
, x
);
1538 double newY2
= wxMax(pt
->sm_controlPointDragStartY
, y
);
1539 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1541 newY1
= pt
->sm_controlPointDragStartY
;
1542 newY2
= newY1
+ pt
->sm_controlPointDragStartHeight
;
1544 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1546 newX1
= pt
->sm_controlPointDragStartX
;
1547 newX2
= newX1
+ pt
->sm_controlPointDragStartWidth
;
1549 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& ((keys
& KEY_SHIFT
) || GetMaintainAspectRatio()))
1551 double newH
= (double)((newX2
- newX1
)*(pt
->sm_controlPointDragStartHeight
/pt
->sm_controlPointDragStartWidth
));
1552 if (pt
->GetY() > pt
->sm_controlPointDragStartY
)
1553 newY2
= (double)(newY1
+ newH
);
1555 newY1
= (double)(newY2
- newH
);
1557 double newWidth
= (double)(newX2
- newX1
);
1558 double newHeight
= (double)(newY2
- newY1
);
1560 if (pt
->m_type
== CONTROL_POINT_VERTICAL
&& GetMaintainAspectRatio())
1562 newWidth
= bound_x
* (newHeight
/bound_y
) ;
1565 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
&& GetMaintainAspectRatio())
1567 newHeight
= bound_y
* (newWidth
/bound_x
) ;
1570 pt
->sm_controlPointDragPosX
= (double)(newX1
+ (newWidth
/2.0));
1571 pt
->sm_controlPointDragPosY
= (double)(newY1
+ (newHeight
/2.0));
1572 if (this->GetFixedWidth())
1575 if (this->GetFixedHeight())
1576 newHeight
= bound_y
;
1578 pt
->sm_controlPointDragEndWidth
= newWidth
;
1579 pt
->sm_controlPointDragEndHeight
= newHeight
;
1580 this->GetEventHandler()->OnDrawOutline(dc
, pt
->sm_controlPointDragPosX
, pt
->sm_controlPointDragPosY
, newWidth
, newHeight
);
1584 void wxShape::OnSizingEndDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int attachment
)
1586 wxClientDC
dc(GetCanvas());
1587 GetCanvas()->PrepareDC(dc
);
1589 m_canvas
->ReleaseMouse();
1590 dc
.SetLogicalFunction(wxCOPY
);
1592 this->ResetControlPoints();
1596 if (!pt->m_eraseObject)
1600 this->SetSize(pt
->sm_controlPointDragEndWidth
, pt
->sm_controlPointDragEndHeight
);
1602 // The next operation could destroy this control point (it does for label objects,
1603 // via formatting the text), so save all values we're going to use, or
1604 // we'll be accessing garbage.
1605 wxShape
*theObject
= this;
1606 wxShapeCanvas
*theCanvas
= m_canvas
;
1607 bool eraseIt
= pt
->m_eraseObject
;
1609 if (theObject
->GetCentreResize())
1610 theObject
->Move(dc
, theObject
->GetX(), theObject
->GetY());
1612 theObject
->Move(dc
, pt
->sm_controlPointDragPosX
, pt
->sm_controlPointDragPosY
);
1616 theObject->Show(TRUE);
1619 // Recursively redraw links if we have a composite.
1620 if (theObject
->GetChildren().Number() > 0)
1621 theObject
->DrawLinks(dc
, -1, TRUE
);
1623 double width
, height
;
1624 theObject
->GetBoundingBoxMax(&width
, &height
);
1625 theObject
->GetEventHandler()->OnEndSize(width
, height
);
1627 if (!theCanvas
->GetQuickEditMode() && eraseIt
) theCanvas
->Redraw(dc
);
1632 // Polygon control points
1634 IMPLEMENT_DYNAMIC_CLASS(wxPolygonControlPoint
, wxControlPoint
)
1636 wxPolygonControlPoint::wxPolygonControlPoint(wxShapeCanvas
*theCanvas
, wxShape
*object
, double size
,
1637 wxRealPoint
*vertex
, double the_xoffset
, double the_yoffset
):
1638 wxControlPoint(theCanvas
, object
, size
, the_xoffset
, the_yoffset
, 0)
1640 m_polygonVertex
= vertex
;
1641 m_originalDistance
= 0.0;
1644 wxPolygonControlPoint::~wxPolygonControlPoint()
1648 // Calculate what new size would be, at end of resize
1649 void wxPolygonControlPoint::CalculateNewSize(double x
, double y
)
1653 GetShape()->GetBoundingBoxMin(&bound_x
, &bound_y
);
1655 double dist
= (double)sqrt((x
- m_shape
->GetX())*(x
- m_shape
->GetX()) +
1656 (y
- m_shape
->GetY())*(y
- m_shape
->GetY()));
1658 m_newSize
.x
= (double)(dist
/this->m_originalDistance
)*this->m_originalSize
.x
;
1659 m_newSize
.y
= (double)(dist
/this->m_originalDistance
)*this->m_originalSize
.y
;
1663 // Implement resizing polygon or moving the vertex.
1664 void wxPolygonControlPoint::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
1666 m_shape
->GetEventHandler()->OnSizingDragLeft(this, draw
, x
, y
, keys
, attachment
);
1669 void wxPolygonControlPoint::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
1671 m_shape
->GetEventHandler()->OnSizingBeginDragLeft(this, x
, y
, keys
, attachment
);
1674 void wxPolygonControlPoint::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
1676 m_shape
->GetEventHandler()->OnSizingEndDragLeft(this, x
, y
, keys
, attachment
);
1679 // Control points ('handles') redirect control to the actual shape, to make it easier
1680 // to override sizing behaviour.
1681 void wxPolygonShape::OnSizingDragLeft(wxControlPoint
* pt
, bool draw
, double x
, double y
, int keys
, int attachment
)
1683 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
1685 wxClientDC
dc(GetCanvas());
1686 GetCanvas()->PrepareDC(dc
);
1688 dc
.SetLogicalFunction(wxXOR
);
1690 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1691 dc
.SetPen(dottedPen
);
1692 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1694 if (0) // keys & KEY_CTRL)
1696 // TODO: mend this code. Currently we rely on altering the
1697 // actual points, but we should assume we're not, as per
1698 // the normal sizing case.
1699 m_canvas
->Snap(&x
, &y
);
1702 ppt
->m_polygonVertex
->x
= x
- this->GetX();
1703 ppt
->m_polygonVertex
->y
= y
- this->GetY();
1706 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1707 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1711 ppt
->CalculateNewSize(x
, y
);
1714 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1715 ppt
->GetNewSize().x
, ppt
->GetNewSize().y
);
1718 void wxPolygonShape::OnSizingBeginDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int attachment
)
1720 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
1722 wxClientDC
dc(GetCanvas());
1723 GetCanvas()->PrepareDC(dc
);
1727 dc
.SetLogicalFunction(wxXOR
);
1731 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1733 double dist
= (double)sqrt((x
- this->GetX())*(x
- this->GetX()) +
1734 (y
- this->GetY())*(y
- this->GetY()));
1735 ppt
->m_originalDistance
= dist
;
1736 ppt
->m_originalSize
.x
= bound_x
;
1737 ppt
->m_originalSize
.y
= bound_y
;
1739 if (ppt
->m_originalDistance
== 0.0) ppt
->m_originalDistance
= (double) 0.0001;
1741 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1742 dc
.SetPen(dottedPen
);
1743 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1745 if (0) // keys & KEY_CTRL)
1747 // TODO: mend this code. Currently we rely on altering the
1748 // actual points, but we should assume we're not, as per
1749 // the normal sizing case.
1750 m_canvas
->Snap(&x
, &y
);
1753 ppt
->m_polygonVertex
->x
= x
- this->GetX();
1754 ppt
->m_polygonVertex
->y
= y
- this->GetY();
1757 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1758 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1762 ppt
->CalculateNewSize(x
, y
);
1765 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1766 ppt
->GetNewSize().x
, ppt
->GetNewSize().y
);
1768 m_canvas
->CaptureMouse();
1771 void wxPolygonShape::OnSizingEndDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int attachment
)
1773 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
1775 wxClientDC
dc(GetCanvas());
1776 GetCanvas()->PrepareDC(dc
);
1778 m_canvas
->ReleaseMouse();
1779 dc
.SetLogicalFunction(wxCOPY
);
1781 // If we're changing shape, must reset the original points
1782 if (keys
& KEY_CTRL
)
1784 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1785 ((wxPolygonShape
*)this)->UpdateOriginalPoints();
1789 SetSize(ppt
->GetNewSize().x
, ppt
->GetNewSize().y
);
1792 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1793 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1796 this->ResetControlPoints();
1797 this->Move(dc
, this->GetX(), this->GetY());
1798 if (!m_canvas
->GetQuickEditMode()) m_canvas
->Redraw(dc
);
1805 IMPLEMENT_DYNAMIC_CLASS(wxShapeRegion
, wxObject
)
1807 wxShapeRegion::wxShapeRegion()
1810 m_font
= g_oglNormalFont
;
1818 m_regionProportionX
= -1.0;
1819 m_regionProportionY
= -1.0;
1820 m_formatMode
= FORMAT_CENTRE_HORIZ
| FORMAT_CENTRE_VERT
;
1822 m_textColour
= "BLACK";
1823 m_penColour
= "BLACK";
1824 m_penStyle
= wxSOLID
;
1825 m_actualColourObject
= NULL
;
1826 m_actualPenObject
= NULL
;
1829 wxShapeRegion::wxShapeRegion(wxShapeRegion
& region
)
1831 m_regionText
= region
.m_regionText
;
1832 m_regionName
= region
.m_regionName
;
1833 m_textColour
= region
.m_textColour
;
1835 m_font
= region
.m_font
;
1836 m_minHeight
= region
.m_minHeight
;
1837 m_minWidth
= region
.m_minWidth
;
1838 m_width
= region
.m_width
;
1839 m_height
= region
.m_height
;
1843 m_regionProportionX
= region
.m_regionProportionX
;
1844 m_regionProportionY
= region
.m_regionProportionY
;
1845 m_formatMode
= region
.m_formatMode
;
1846 m_actualColourObject
= NULL
;
1847 m_actualPenObject
= NULL
;
1848 m_penStyle
= region
.m_penStyle
;
1849 m_penColour
= region
.m_penColour
;
1852 wxNode
*node
= region
.m_formattedText
.First();
1855 wxShapeTextLine
*line
= (wxShapeTextLine
*)node
->Data();
1856 wxShapeTextLine
*new_line
=
1857 new wxShapeTextLine(line
->GetX(), line
->GetY(), line
->GetText());
1858 m_formattedText
.Append(new_line
);
1859 node
= node
->Next();
1863 wxShapeRegion::~wxShapeRegion()
1868 void wxShapeRegion::ClearText()
1870 wxNode
*node
= m_formattedText
.First();
1873 wxShapeTextLine
*line
= (wxShapeTextLine
*)node
->Data();
1874 wxNode
*next
= node
->Next();
1881 void wxShapeRegion::SetFont(wxFont
*f
)
1886 void wxShapeRegion::SetMinSize(double w
, double h
)
1892 void wxShapeRegion::SetSize(double w
, double h
)
1898 void wxShapeRegion::SetPosition(double xp
, double yp
)
1904 void wxShapeRegion::SetProportions(double xp
, double yp
)
1906 m_regionProportionX
= xp
;
1907 m_regionProportionY
= yp
;
1910 void wxShapeRegion::SetFormatMode(int mode
)
1912 m_formatMode
= mode
;
1915 void wxShapeRegion::SetColour(const wxString
& col
)
1918 m_actualColourObject
= NULL
;
1921 wxColour
*wxShapeRegion::GetActualColourObject()
1923 if (!m_actualColourObject
)
1924 m_actualColourObject
= wxTheColourDatabase
->FindColour(GetColour());
1925 if (!m_actualColourObject
)
1926 m_actualColourObject
= wxBLACK
;
1927 return m_actualColourObject
;
1930 void wxShapeRegion::SetPenColour(const wxString
& col
)
1933 m_actualPenObject
= NULL
;
1936 // Returns NULL if the pen is invisible
1937 // (different to pen being transparent; indicates that
1938 // region boundary should not be drawn.)
1939 wxPen
*wxShapeRegion::GetActualPen()
1941 if (m_actualPenObject
)
1942 return m_actualPenObject
;
1944 if (!m_penColour
) return NULL
;
1945 if (m_penColour
== "Invisible")
1947 m_actualPenObject
= wxThePenList
->FindOrCreatePen(m_penColour
, 1, m_penStyle
);
1948 return m_actualPenObject
;