1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Basic OGL classes (2)
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "basicp.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include <wx/wxprec.h>
27 #include <wx/wxexpr.h>
47 // Control point types
48 // Rectangle and most other shapes
49 #define CONTROL_POINT_VERTICAL 1
50 #define CONTROL_POINT_HORIZONTAL 2
51 #define CONTROL_POINT_DIAGONAL 3
54 #define CONTROL_POINT_ENDPOINT_TO 4
55 #define CONTROL_POINT_ENDPOINT_FROM 5
56 #define CONTROL_POINT_LINE 6
58 // Two stage construction: need to call Create
59 IMPLEMENT_DYNAMIC_CLASS(wxPolygonShape
, wxShape
)
61 wxPolygonShape::wxPolygonShape()
64 m_originalPoints
= NULL
;
67 void wxPolygonShape::Create(wxList
*the_points
)
71 m_originalPoints
= the_points
;
73 // Duplicate the list of points
74 m_points
= new wxList
;
76 wxNode
*node
= the_points
->First();
79 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
80 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
81 m_points
->Append((wxObject
*) new_point
);
84 CalculateBoundingBox();
85 m_originalWidth
= m_boundWidth
;
86 m_originalHeight
= m_boundHeight
;
87 SetDefaultRegionSize();
90 wxPolygonShape::~wxPolygonShape()
95 void wxPolygonShape::ClearPoints()
99 wxNode
*node
= m_points
->First();
102 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
105 node
= m_points
->First();
110 if (m_originalPoints
)
112 wxNode
*node
= m_originalPoints
->First();
115 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
118 node
= m_originalPoints
->First();
120 delete m_originalPoints
;
121 m_originalPoints
= NULL
;
126 // Width and height. Centre of object is centre of box.
127 void wxPolygonShape::GetBoundingBoxMin(double *width
, double *height
)
129 *width
= m_boundWidth
;
130 *height
= m_boundHeight
;
133 void wxPolygonShape::CalculateBoundingBox()
135 // Calculate bounding box at construction (and presumably resize) time
137 double right
= -10000;
139 double bottom
= -10000;
141 wxNode
*node
= m_points
->First();
144 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
145 if (point
->x
< left
) left
= point
->x
;
146 if (point
->x
> right
) right
= point
->x
;
148 if (point
->y
< top
) top
= point
->y
;
149 if (point
->y
> bottom
) bottom
= point
->y
;
153 m_boundWidth
= right
- left
;
154 m_boundHeight
= bottom
- top
;
157 // Recalculates the centre of the polygon, and
158 // readjusts the point offsets accordingly.
159 // Necessary since the centre of the polygon
160 // is expected to be the real centre of the bounding
162 void wxPolygonShape::CalculatePolygonCentre()
165 double right
= -10000;
167 double bottom
= -10000;
169 wxNode
*node
= m_points
->First();
172 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
173 if (point
->x
< left
) left
= point
->x
;
174 if (point
->x
> right
) right
= point
->x
;
176 if (point
->y
< top
) top
= point
->y
;
177 if (point
->y
> bottom
) bottom
= point
->y
;
181 double bwidth
= right
- left
;
182 double bheight
= bottom
- top
;
184 double newCentreX
= (double)(left
+ (bwidth
/2.0));
185 double newCentreY
= (double)(top
+ (bheight
/2.0));
187 node
= m_points
->First();
190 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
191 point
->x
-= newCentreX
;
192 point
->y
-= newCentreY
;
195 m_xpos
+= newCentreX
;
196 m_ypos
+= newCentreY
;
199 bool PolylineHitTest(double n
, double xvec
[], double yvec
[],
200 double x1
, double y1
, double x2
, double y2
)
204 double lastx
= xvec
[0];
205 double lasty
= yvec
[0];
207 double min_ratio
= 1.0;
212 for (i
= 1; i
< n
; i
++)
214 oglCheckLineIntersection(x1
, y1
, x2
, y2
, lastx
, lasty
, xvec
[i
], yvec
[i
],
215 &line_ratio
, &other_ratio
);
216 if (line_ratio
!= 1.0)
218 // sprintf(buf, "Line ratio = %.2f, other ratio = %.2f\n", line_ratio, other_ratio);
219 // ClipsErrorFunction(buf);
223 if (line_ratio
< min_ratio
)
224 min_ratio
= line_ratio
;
227 // Do last (implicit) line if last and first doubles are not identical
228 if (!(xvec
[0] == lastx
&& yvec
[0] == lasty
))
230 oglCheckLineIntersection(x1
, y1
, x2
, y2
, lastx
, lasty
, xvec
[0], yvec
[0],
231 &line_ratio
, &other_ratio
);
232 if (line_ratio
!= 1.0)
234 // sprintf(buf, "Line ratio = %.2f, other ratio = %.2f\n", line_ratio, other_ratio);
235 // ClipsErrorFunction(buf);
237 if (line_ratio
< min_ratio
)
238 min_ratio
= line_ratio
;
240 // ClipsErrorFunction("\n");
244 bool wxPolygonShape::HitTest(double x
, double y
, int *attachment
, double *distance
)
246 // Imagine four lines radiating from this point. If all of these lines hit the polygon,
247 // we're inside it, otherwise we're not. Obviously we'd need more radiating lines
248 // to be sure of correct results for very strange (concave) shapes.
249 double endPointsX
[4];
250 double endPointsY
[4];
253 endPointsY
[0] = (double)(y
- 1000.0);
255 endPointsX
[1] = (double)(x
+ 1000.0);
259 endPointsY
[2] = (double)(y
+ 1000.0);
261 endPointsX
[3] = (double)(x
- 1000.0);
264 // Store polygon points in an array
265 int np
= m_points
->Number();
266 double *xpoints
= new double[np
];
267 double *ypoints
= new double[np
];
268 wxNode
*node
= m_points
->First();
272 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
273 xpoints
[i
] = point
->x
+ m_xpos
;
274 ypoints
[i
] = point
->y
+ m_ypos
;
279 // We assume it's inside the polygon UNLESS one or more
280 // lines don't hit the outline.
281 bool isContained
= TRUE
;
284 for (i
= 0; i
< noPoints
; i
++)
286 if (!PolylineHitTest(np
, xpoints
, ypoints
, x
, y
, endPointsX
[i
], endPointsY
[i
]))
291 ClipsErrorFunction("It's a hit!\n");
293 ClipsErrorFunction("No hit.\n");
301 int nearest_attachment
= 0;
303 // If a hit, check the attachment points within the object.
304 int n
= GetNumberOfAttachments();
305 double nearest
= 999999.0;
307 for (i
= 0; i
< n
; i
++)
310 if (GetAttachmentPositionEdge(i
, &xp
, &yp
))
312 double l
= (double)sqrt(((xp
- x
) * (xp
- x
)) +
313 ((yp
- y
) * (yp
- y
)));
317 nearest_attachment
= i
;
321 *attachment
= nearest_attachment
;
326 // Really need to be able to reset the shape! Otherwise, if the
327 // points ever go to zero, we've lost it, and can't resize.
328 void wxPolygonShape::SetSize(double new_width
, double new_height
, bool recursive
)
330 SetAttachmentSize(new_width
, new_height
);
332 // Multiply all points by proportion of new size to old size
333 double x_proportion
= (double)(fabs(new_width
/m_originalWidth
));
334 double y_proportion
= (double)(fabs(new_height
/m_originalHeight
));
336 wxNode
*node
= m_points
->First();
337 wxNode
*original_node
= m_originalPoints
->First();
338 while (node
&& original_node
)
340 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
341 wxRealPoint
*original_point
= (wxRealPoint
*)original_node
->Data();
343 point
->x
= (original_point
->x
* x_proportion
);
344 point
->y
= (original_point
->y
* y_proportion
);
347 original_node
= original_node
->Next();
350 // CalculateBoundingBox();
351 m_boundWidth
= (double)fabs(new_width
);
352 m_boundHeight
= (double)fabs(new_height
);
353 SetDefaultRegionSize();
356 // Make the original points the same as the working points
357 void wxPolygonShape::UpdateOriginalPoints()
359 if (!m_originalPoints
) m_originalPoints
= new wxList
;
360 wxNode
*original_node
= m_originalPoints
->First();
361 while (original_node
)
363 wxNode
*next_node
= original_node
->Next();
364 wxRealPoint
*original_point
= (wxRealPoint
*)original_node
->Data();
365 delete original_point
;
366 delete original_node
;
368 original_node
= next_node
;
371 wxNode
*node
= m_points
->First();
374 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
375 wxRealPoint
*original_point
= new wxRealPoint(point
->x
, point
->y
);
376 m_originalPoints
->Append((wxObject
*) original_point
);
380 CalculateBoundingBox();
381 m_originalWidth
= m_boundWidth
;
382 m_originalHeight
= m_boundHeight
;
385 void wxPolygonShape::AddPolygonPoint(int pos
)
387 wxNode
*node
= m_points
->Nth(pos
);
388 if (!node
) node
= m_points
->First();
389 wxRealPoint
*firstPoint
= (wxRealPoint
*)node
->Data();
391 wxNode
*node2
= m_points
->Nth(pos
+ 1);
392 if (!node2
) node2
= m_points
->First();
393 wxRealPoint
*secondPoint
= (wxRealPoint
*)node2
->Data();
395 double x
= (double)((secondPoint
->x
- firstPoint
->x
)/2.0 + firstPoint
->x
);
396 double y
= (double)((secondPoint
->y
- firstPoint
->y
)/2.0 + firstPoint
->y
);
397 wxRealPoint
*point
= new wxRealPoint(x
, y
);
399 if (pos
>= (m_points
->Number() - 1))
400 m_points
->Append((wxObject
*) point
);
402 m_points
->Insert(node2
, (wxObject
*) point
);
404 UpdateOriginalPoints();
408 DeleteControlPoints();
413 void wxPolygonShape::DeletePolygonPoint(int pos
)
415 wxNode
*node
= m_points
->Nth(pos
);
418 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
421 UpdateOriginalPoints();
424 DeleteControlPoints();
430 // Assume (x1, y1) is centre of box (most generally, line end at box)
431 bool wxPolygonShape::GetPerimeterPoint(double x1
, double y1
,
432 double x2
, double y2
,
433 double *x3
, double *y3
)
435 int n
= m_points
->Number();
437 // First check for situation where the line is vertical,
438 // and we would want to connect to a point on that vertical --
439 // oglFindEndForPolyline can't cope with this (the arrow
440 // gets drawn to the wrong place).
441 if ((m_attachmentMode
== ATTACHMENT_MODE_NONE
) && (x1
== x2
))
443 // Look for the point we'd be connecting to. This is
445 wxNode
*node
= m_points
->First();
448 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
451 if ((y2
> y1
) && (point
->y
> 0.0))
453 *x3
= point
->x
+ m_xpos
;
454 *y3
= point
->y
+ m_ypos
;
457 else if ((y2
< y1
) && (point
->y
< 0.0))
459 *x3
= point
->x
+ m_xpos
;
460 *y3
= point
->y
+ m_ypos
;
468 double *xpoints
= new double[n
];
469 double *ypoints
= new double[n
];
471 wxNode
*node
= m_points
->First();
475 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
476 xpoints
[i
] = point
->x
+ m_xpos
;
477 ypoints
[i
] = point
->y
+ m_ypos
;
482 oglFindEndForPolyline(n
, xpoints
, ypoints
,
483 x1
, y1
, x2
, y2
, x3
, y3
);
491 void wxPolygonShape::OnDraw(wxDC
& dc
)
493 int n
= m_points
->Number();
494 wxPoint
*intPoints
= new wxPoint
[n
];
496 for (i
= 0; i
< n
; i
++)
498 wxRealPoint
* point
= (wxRealPoint
*) m_points
->Nth(i
)->Data();
499 intPoints
[i
].x
= WXROUND(point
->x
);
500 intPoints
[i
].y
= WXROUND(point
->y
);
503 if (m_shadowMode
!= SHADOW_NONE
)
506 dc
.SetBrush(m_shadowBrush
);
507 dc
.SetPen(g_oglTransparentPen
);
509 dc
.DrawPolygon(n
, intPoints
, WXROUND(m_xpos
+ m_shadowOffsetX
), WXROUND(m_ypos
+ m_shadowOffsetY
));
514 if (m_pen
->GetWidth() == 0)
515 dc
.SetPen(g_oglTransparentPen
);
520 dc
.SetBrush(m_brush
);
521 dc
.DrawPolygon(n
, intPoints
, WXROUND(m_xpos
), WXROUND(m_ypos
));
526 void wxPolygonShape::OnDrawOutline(wxDC
& dc
, double x
, double y
, double w
, double h
)
528 dc
.SetBrush(wxTRANSPARENT_BRUSH
);
529 // Multiply all points by proportion of new size to old size
530 double x_proportion
= (double)(fabs(w
/m_originalWidth
));
531 double y_proportion
= (double)(fabs(h
/m_originalHeight
));
533 int n
= m_originalPoints
->Number();
534 wxPoint
*intPoints
= new wxPoint
[n
];
536 for (i
= 0; i
< n
; i
++)
538 wxRealPoint
* point
= (wxRealPoint
*) m_originalPoints
->Nth(i
)->Data();
539 intPoints
[i
].x
= WXROUND(x_proportion
* point
->x
);
540 intPoints
[i
].y
= WXROUND(y_proportion
* point
->y
);
542 dc
.DrawPolygon(n
, intPoints
, WXROUND(x
), WXROUND(y
));
546 // Make as many control points as there are vertices.
547 void wxPolygonShape::MakeControlPoints()
549 wxNode
*node
= m_points
->First();
552 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
553 wxPolygonControlPoint
*control
= new wxPolygonControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
,
554 point
, point
->x
, point
->y
);
555 m_canvas
->AddShape(control
);
556 m_controlPoints
.Append(control
);
561 void wxPolygonShape::ResetControlPoints()
563 wxNode
*node
= m_points
->First();
564 wxNode
*controlPointNode
= m_controlPoints
.First();
565 while (node
&& controlPointNode
)
567 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
568 wxPolygonControlPoint
*controlPoint
= (wxPolygonControlPoint
*)controlPointNode
->Data();
570 controlPoint
->m_xoffset
= point
->x
;
571 controlPoint
->m_yoffset
= point
->y
;
572 controlPoint
->m_polygonVertex
= point
;
575 controlPointNode
= controlPointNode
->Next();
581 void wxPolygonShape::WriteAttributes(wxExpr
*clause
)
583 wxShape::WriteAttributes(clause
);
585 clause
->AddAttributeValue("x", m_xpos
);
586 clause
->AddAttributeValue("y", m_ypos
);
588 // Make a list of lists for the coordinates
589 wxExpr
*list
= new wxExpr(wxExprList
);
590 wxNode
*node
= m_points
->First();
593 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
594 wxExpr
*point_list
= new wxExpr(wxExprList
);
595 wxExpr
*x_expr
= new wxExpr((double)point
->x
);
596 wxExpr
*y_expr
= new wxExpr((double)point
->y
);
598 point_list
->Append(x_expr
);
599 point_list
->Append(y_expr
);
600 list
->Append(point_list
);
604 clause
->AddAttributeValue("points", list
);
606 // Save the original (unscaled) points
607 list
= new wxExpr(wxExprList
);
608 node
= m_originalPoints
->First();
611 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
612 wxExpr
*point_list
= new wxExpr(wxExprList
);
613 wxExpr
*x_expr
= new wxExpr((double) point
->x
);
614 wxExpr
*y_expr
= new wxExpr((double) point
->y
);
615 point_list
->Append(x_expr
);
616 point_list
->Append(y_expr
);
617 list
->Append(point_list
);
621 clause
->AddAttributeValue("m_originalPoints", list
);
624 void wxPolygonShape::ReadAttributes(wxExpr
*clause
)
626 wxShape::ReadAttributes(clause
);
628 // Read a list of lists
629 m_points
= new wxList
;
630 m_originalPoints
= new wxList
;
632 wxExpr
*points_list
= NULL
;
633 clause
->AssignAttributeValue("points", &points_list
);
635 // If no points_list, don't crash!! Assume a diamond instead.
636 double the_height
= 100.0;
637 double the_width
= 100.0;
640 wxRealPoint
*point
= new wxRealPoint(0.0, (-the_height
/2));
641 m_points
->Append((wxObject
*) point
);
643 point
= new wxRealPoint((the_width
/2), 0.0);
644 m_points
->Append((wxObject
*) point
);
646 point
= new wxRealPoint(0.0, (the_height
/2));
647 m_points
->Append((wxObject
*) point
);
649 point
= new wxRealPoint((-the_width
/2), 0.0);
650 m_points
->Append((wxObject
*) point
);
652 point
= new wxRealPoint(0.0, (-the_height
/2));
653 m_points
->Append((wxObject
*) point
);
657 wxExpr
*node
= points_list
->value
.first
;
661 wxExpr
*xexpr
= node
->value
.first
;
662 long x
= xexpr
->IntegerValue();
664 wxExpr
*yexpr
= xexpr
->next
;
665 long y
= yexpr
->IntegerValue();
667 wxRealPoint
*point
= new wxRealPoint((double)x
, (double)y
);
668 m_points
->Append((wxObject
*) point
);
675 clause
->AssignAttributeValue("m_originalPoints", &points_list
);
677 // If no points_list, don't crash!! Assume a diamond instead.
680 wxRealPoint
*point
= new wxRealPoint(0.0, (-the_height
/2));
681 m_originalPoints
->Append((wxObject
*) point
);
683 point
= new wxRealPoint((the_width
/2), 0.0);
684 m_originalPoints
->Append((wxObject
*) point
);
686 point
= new wxRealPoint(0.0, (the_height
/2));
687 m_originalPoints
->Append((wxObject
*) point
);
689 point
= new wxRealPoint((-the_width
/2), 0.0);
690 m_originalPoints
->Append((wxObject
*) point
);
692 point
= new wxRealPoint(0.0, (-the_height
/2));
693 m_originalPoints
->Append((wxObject
*) point
);
695 m_originalWidth
= the_width
;
696 m_originalHeight
= the_height
;
700 wxExpr
*node
= points_list
->value
.first
;
703 double max_x
= -1000;
704 double max_y
= -1000;
707 wxExpr
*xexpr
= node
->value
.first
;
708 long x
= xexpr
->IntegerValue();
710 wxExpr
*yexpr
= xexpr
->next
;
711 long y
= yexpr
->IntegerValue();
713 wxRealPoint
*point
= new wxRealPoint((double)x
, (double)y
);
714 m_originalPoints
->Append((wxObject
*) point
);
727 m_originalWidth
= max_x
- min_x
;
728 m_originalHeight
= max_y
- min_y
;
731 CalculateBoundingBox();
735 void wxPolygonShape::Copy(wxShape
& copy
)
739 wxASSERT( copy
.IsKindOf(CLASSINFO(wxPolygonShape
)) );
741 wxPolygonShape
& polyCopy
= (wxPolygonShape
&) copy
;
743 polyCopy
.ClearPoints();
745 polyCopy
.m_points
= new wxList
;
746 polyCopy
.m_originalPoints
= new wxList
;
748 wxNode
*node
= m_points
->First();
751 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
752 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
753 polyCopy
.m_points
->Append((wxObject
*) new_point
);
756 node
= m_originalPoints
->First();
759 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
760 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
761 polyCopy
.m_originalPoints
->Append((wxObject
*) new_point
);
764 polyCopy
.m_boundWidth
= m_boundWidth
;
765 polyCopy
.m_boundHeight
= m_boundHeight
;
766 polyCopy
.m_originalWidth
= m_originalWidth
;
767 polyCopy
.m_originalHeight
= m_originalHeight
;
770 int wxPolygonShape::GetNumberOfAttachments() const
772 int maxN
= (m_points
? (m_points
->Number() - 1) : 0);
773 wxNode
*node
= m_attachmentPoints
.First();
776 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
777 if (point
->m_id
> maxN
)
784 bool wxPolygonShape::GetAttachmentPosition(int attachment
, double *x
, double *y
,
785 int nth
, int no_arcs
, wxLineShape
*line
)
787 if ((m_attachmentMode
== ATTACHMENT_MODE_EDGE
) && m_points
&& attachment
< m_points
->Number())
789 wxRealPoint
*point
= (wxRealPoint
*)m_points
->Nth(attachment
)->Data();
790 *x
= point
->x
+ m_xpos
;
791 *y
= point
->y
+ m_ypos
;
795 { return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
); }
798 bool wxPolygonShape::AttachmentIsValid(int attachment
)
803 if ((attachment
>= 0) && (attachment
< m_points
->Number()))
806 wxNode
*node
= m_attachmentPoints
.First();
809 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
810 if (point
->m_id
== attachment
)
817 // Rotate about the given axis by the given amount in radians
818 void wxPolygonShape::Rotate(double x
, double y
, double theta
)
820 double actualTheta
= theta
-m_rotation
;
822 // Rotate attachment points
823 double sinTheta
= (double)sin(actualTheta
);
824 double cosTheta
= (double)cos(actualTheta
);
825 wxNode
*node
= m_attachmentPoints
.First();
828 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
829 double x1
= point
->m_x
;
830 double y1
= point
->m_y
;
831 point
->m_x
= x1
*cosTheta
- y1
*sinTheta
+ x
*(1.0 - cosTheta
) + y
*sinTheta
;
832 point
->m_y
= x1
*sinTheta
+ y1
*cosTheta
+ y
*(1.0 - cosTheta
) + x
*sinTheta
;
836 node
= m_points
->First();
839 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
840 double x1
= point
->x
;
841 double y1
= point
->y
;
842 point
->x
= x1
*cosTheta
- y1
*sinTheta
+ x
*(1.0 - cosTheta
) + y
*sinTheta
;
843 point
->y
= x1
*sinTheta
+ y1
*cosTheta
+ y
*(1.0 - cosTheta
) + x
*sinTheta
;
846 node
= m_originalPoints
->First();
849 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
850 double x1
= point
->x
;
851 double y1
= point
->y
;
852 point
->x
= x1
*cosTheta
- y1
*sinTheta
+ x
*(1.0 - cosTheta
) + y
*sinTheta
;
853 point
->y
= x1
*sinTheta
+ y1
*cosTheta
+ y
*(1.0 - cosTheta
) + x
*sinTheta
;
859 CalculatePolygonCentre();
860 CalculateBoundingBox();
861 ResetControlPoints();
866 IMPLEMENT_DYNAMIC_CLASS(wxRectangleShape
, wxShape
)
868 wxRectangleShape::wxRectangleShape(double w
, double h
)
870 m_width
= w
; m_height
= h
; m_cornerRadius
= 0.0;
871 SetDefaultRegionSize();
874 void wxRectangleShape::OnDraw(wxDC
& dc
)
876 double x1
= (double)(m_xpos
- m_width
/2.0);
877 double y1
= (double)(m_ypos
- m_height
/2.0);
879 if (m_shadowMode
!= SHADOW_NONE
)
882 dc
.SetBrush(m_shadowBrush
);
883 dc
.SetPen(g_oglTransparentPen
);
885 if (m_cornerRadius
!= 0.0)
886 dc
.DrawRoundedRectangle(WXROUND(x1
+ m_shadowOffsetX
), WXROUND(y1
+ m_shadowOffsetY
),
887 WXROUND(m_width
), WXROUND(m_height
), m_cornerRadius
);
889 dc
.DrawRectangle(WXROUND(x1
+ m_shadowOffsetX
), WXROUND(y1
+ m_shadowOffsetY
), WXROUND(m_width
), WXROUND(m_height
));
894 if (m_pen
->GetWidth() == 0)
895 dc
.SetPen(g_oglTransparentPen
);
900 dc
.SetBrush(m_brush
);
902 if (m_cornerRadius
!= 0.0)
903 dc
.DrawRoundedRectangle(WXROUND(x1
), WXROUND(y1
), WXROUND(m_width
), WXROUND(m_height
), m_cornerRadius
);
905 dc
.DrawRectangle(WXROUND(x1
), WXROUND(y1
), WXROUND(m_width
), WXROUND(m_height
));
908 void wxRectangleShape::GetBoundingBoxMin(double *the_width
, double *the_height
)
910 *the_width
= m_width
;
911 *the_height
= m_height
;
914 void wxRectangleShape::SetSize(double x
, double y
, bool recursive
)
916 SetAttachmentSize(x
, y
);
917 m_width
= (double)wxMax(x
, 1.0);
918 m_height
= (double)wxMax(y
, 1.0);
919 SetDefaultRegionSize();
922 void wxRectangleShape::SetCornerRadius(double rad
)
924 m_cornerRadius
= rad
;
927 // Assume (x1, y1) is centre of box (most generally, line end at box)
928 bool wxRectangleShape::GetPerimeterPoint(double x1
, double y1
,
929 double x2
, double y2
,
930 double *x3
, double *y3
)
932 double bound_x
, bound_y
;
933 GetBoundingBoxMax(&bound_x
, &bound_y
);
934 oglFindEndForBox(bound_x
, bound_y
, m_xpos
, m_ypos
, x2
, y2
, x3
, y3
);
940 void wxRectangleShape::WriteAttributes(wxExpr
*clause
)
942 wxShape::WriteAttributes(clause
);
943 clause
->AddAttributeValue("x", m_xpos
);
944 clause
->AddAttributeValue("y", m_ypos
);
946 clause
->AddAttributeValue("width", m_width
);
947 clause
->AddAttributeValue("height", m_height
);
948 if (m_cornerRadius
!= 0.0)
949 clause
->AddAttributeValue("corner", m_cornerRadius
);
952 void wxRectangleShape::ReadAttributes(wxExpr
*clause
)
954 wxShape::ReadAttributes(clause
);
955 clause
->AssignAttributeValue("width", &m_width
);
956 clause
->AssignAttributeValue("height", &m_height
);
957 clause
->AssignAttributeValue("corner", &m_cornerRadius
);
959 // In case we're reading an old file, set the region's size
960 if (m_regions
.Number() == 1)
962 wxShapeRegion
*region
= (wxShapeRegion
*)m_regions
.First()->Data();
963 region
->SetSize(m_width
, m_height
);
968 void wxRectangleShape::Copy(wxShape
& copy
)
972 wxASSERT( copy
.IsKindOf(CLASSINFO(wxRectangleShape
)) );
974 wxRectangleShape
& rectCopy
= (wxRectangleShape
&) copy
;
975 rectCopy
.m_width
= m_width
;
976 rectCopy
.m_height
= m_height
;
977 rectCopy
.m_cornerRadius
= m_cornerRadius
;
980 int wxRectangleShape::GetNumberOfAttachments() const
982 return wxShape::GetNumberOfAttachments();
986 // There are 4 attachment points on a rectangle - 0 = top, 1 = right, 2 = bottom,
988 bool wxRectangleShape::GetAttachmentPosition(int attachment
, double *x
, double *y
,
989 int nth
, int no_arcs
, wxLineShape
*line
)
991 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
994 // Text object (no box)
996 IMPLEMENT_DYNAMIC_CLASS(wxTextShape
, wxRectangleShape
)
998 wxTextShape::wxTextShape(double width
, double height
):
999 wxRectangleShape(width
, height
)
1003 void wxTextShape::OnDraw(wxDC
& dc
)
1007 void wxTextShape::Copy(wxShape
& copy
)
1009 wxRectangleShape::Copy(copy
);
1013 void wxTextShape::WriteAttributes(wxExpr
*clause
)
1015 wxRectangleShape::WriteAttributes(clause
);
1021 IMPLEMENT_DYNAMIC_CLASS(wxEllipseShape
, wxShape
)
1023 wxEllipseShape::wxEllipseShape(double w
, double h
)
1025 m_width
= w
; m_height
= h
;
1026 SetDefaultRegionSize();
1029 void wxEllipseShape::GetBoundingBoxMin(double *w
, double *h
)
1031 *w
= m_width
; *h
= m_height
;
1034 bool wxEllipseShape::GetPerimeterPoint(double x1
, double y1
,
1035 double x2
, double y2
,
1036 double *x3
, double *y3
)
1038 double bound_x
, bound_y
;
1039 GetBoundingBoxMax(&bound_x
, &bound_y
);
1041 // oglFindEndForBox(bound_x, bound_y, m_xpos, m_ypos, x2, y2, x3, y3);
1042 oglDrawArcToEllipse(m_xpos
, m_ypos
, bound_x
, bound_y
, x2
, y2
, x1
, y1
, x3
, y3
);
1047 void wxEllipseShape::OnDraw(wxDC
& dc
)
1049 if (m_shadowMode
!= SHADOW_NONE
)
1052 dc
.SetBrush(m_shadowBrush
);
1053 dc
.SetPen(g_oglTransparentPen
);
1054 dc
.DrawEllipse((long) ((m_xpos
- GetWidth()/2) + m_shadowOffsetX
),
1055 (long) ((m_ypos
- GetHeight()/2) + m_shadowOffsetY
),
1056 (long) GetWidth(), (long) GetHeight());
1061 if (m_pen
->GetWidth() == 0)
1062 dc
.SetPen(g_oglTransparentPen
);
1067 dc
.SetBrush(m_brush
);
1068 dc
.DrawEllipse((long) (m_xpos
- GetWidth()/2), (long) (m_ypos
- GetHeight()/2), (long) GetWidth(), (long) GetHeight());
1071 void wxEllipseShape::SetSize(double x
, double y
, bool recursive
)
1073 SetAttachmentSize(x
, y
);
1076 SetDefaultRegionSize();
1080 void wxEllipseShape::WriteAttributes(wxExpr
*clause
)
1082 wxShape::WriteAttributes(clause
);
1083 clause
->AddAttributeValue("x", m_xpos
);
1084 clause
->AddAttributeValue("y", m_ypos
);
1086 clause
->AddAttributeValue("width", m_width
);
1087 clause
->AddAttributeValue("height", m_height
);
1090 void wxEllipseShape::ReadAttributes(wxExpr
*clause
)
1092 wxShape::ReadAttributes(clause
);
1093 clause
->AssignAttributeValue("width", &m_width
);
1094 clause
->AssignAttributeValue("height", &m_height
);
1096 // In case we're reading an old file, set the region's size
1097 if (m_regions
.Number() == 1)
1099 wxShapeRegion
*region
= (wxShapeRegion
*)m_regions
.First()->Data();
1100 region
->SetSize(m_width
, m_height
);
1105 void wxEllipseShape::Copy(wxShape
& copy
)
1107 wxShape::Copy(copy
);
1109 wxASSERT( copy
.IsKindOf(CLASSINFO(wxEllipseShape
)) );
1111 wxEllipseShape
& ellipseCopy
= (wxEllipseShape
&) copy
;
1113 ellipseCopy
.m_width
= m_width
;
1114 ellipseCopy
.m_height
= m_height
;
1117 int wxEllipseShape::GetNumberOfAttachments() const
1119 return wxShape::GetNumberOfAttachments();
1122 // There are 4 attachment points on an ellipse - 0 = top, 1 = right, 2 = bottom,
1124 bool wxEllipseShape::GetAttachmentPosition(int attachment
, double *x
, double *y
,
1125 int nth
, int no_arcs
, wxLineShape
*line
)
1127 if (m_attachmentMode
== ATTACHMENT_MODE_BRANCHING
)
1128 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
1130 if (m_attachmentMode
!= ATTACHMENT_MODE_NONE
)
1132 double top
= (double)(m_ypos
+ m_height
/2.0);
1133 double bottom
= (double)(m_ypos
- m_height
/2.0);
1134 double left
= (double)(m_xpos
- m_width
/2.0);
1135 double right
= (double)(m_xpos
+ m_width
/2.0);
1137 int physicalAttachment
= LogicalToPhysicalAttachment(attachment
);
1139 switch (physicalAttachment
)
1143 if (m_spaceAttachments
)
1144 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
1147 // We now have the point on the bounding box: but get the point on the ellipse
1148 // by imagining a vertical line from (*x, m_ypos - m_height- 500) to (*x, m_ypos) intersecting
1150 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, *x
, (double)(m_ypos
-m_height
-500), *x
, m_ypos
, x
, y
);
1156 if (m_spaceAttachments
)
1157 *y
= bottom
+ (nth
+ 1)*m_height
/(no_arcs
+ 1);
1159 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, (double)(m_xpos
+m_width
+500), *y
, m_xpos
, *y
, x
, y
);
1164 if (m_spaceAttachments
)
1165 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
1168 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, *x
, (double)(m_ypos
+m_height
+500), *x
, m_ypos
, x
, y
);
1174 if (m_spaceAttachments
)
1175 *y
= bottom
+ (nth
+ 1)*m_height
/(no_arcs
+ 1);
1177 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, (double)(m_xpos
-m_width
-500), *y
, m_xpos
, *y
, x
, y
);
1182 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
1189 { *x
= m_xpos
; *y
= m_ypos
; return TRUE
; }
1194 IMPLEMENT_DYNAMIC_CLASS(wxCircleShape
, wxEllipseShape
)
1196 wxCircleShape::wxCircleShape(double diameter
):wxEllipseShape(diameter
, diameter
)
1198 SetMaintainAspectRatio(TRUE
);
1201 void wxCircleShape::Copy(wxShape
& copy
)
1203 wxEllipseShape::Copy(copy
);
1206 bool wxCircleShape::GetPerimeterPoint(double x1
, double y1
,
1207 double x2
, double y2
,
1208 double *x3
, double *y3
)
1210 oglFindEndForCircle(m_width
/2,
1211 m_xpos
, m_ypos
, // Centre of circle
1212 x2
, y2
, // Other end of line
1220 double wxControlPoint::sm_controlPointDragStartX
= 0.0;
1221 double wxControlPoint::sm_controlPointDragStartY
= 0.0;
1222 double wxControlPoint::sm_controlPointDragStartWidth
= 0.0;
1223 double wxControlPoint::sm_controlPointDragStartHeight
= 0.0;
1224 double wxControlPoint::sm_controlPointDragEndWidth
= 0.0;
1225 double wxControlPoint::sm_controlPointDragEndHeight
= 0.0;
1226 double wxControlPoint::sm_controlPointDragPosX
= 0.0;
1227 double wxControlPoint::sm_controlPointDragPosY
= 0.0;
1229 IMPLEMENT_DYNAMIC_CLASS(wxControlPoint
, wxRectangleShape
)
1231 wxControlPoint::wxControlPoint(wxShapeCanvas
*theCanvas
, wxShape
*object
, double size
, double the_xoffset
, double the_yoffset
, int the_type
):wxRectangleShape(size
, size
)
1233 m_canvas
= theCanvas
;
1235 m_xoffset
= the_xoffset
;
1236 m_yoffset
= the_yoffset
;
1238 SetPen(g_oglBlackForegroundPen
);
1239 SetBrush(wxBLACK_BRUSH
);
1242 m_eraseObject
= TRUE
;
1245 wxControlPoint::~wxControlPoint()
1249 // Don't even attempt to draw any text - waste of time!
1250 void wxControlPoint::OnDrawContents(wxDC
& dc
)
1254 void wxControlPoint::OnDraw(wxDC
& dc
)
1256 m_xpos
= m_shape
->GetX() + m_xoffset
;
1257 m_ypos
= m_shape
->GetY() + m_yoffset
;
1258 wxRectangleShape::OnDraw(dc
);
1261 void wxControlPoint::OnErase(wxDC
& dc
)
1263 wxRectangleShape::OnErase(dc
);
1266 // Implement resizing of canvas object
1267 void wxControlPoint::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
1269 m_shape
->GetEventHandler()->OnSizingDragLeft(this, draw
, x
, y
, keys
, attachment
);
1272 void wxControlPoint::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
1274 m_shape
->GetEventHandler()->OnSizingBeginDragLeft(this, x
, y
, keys
, attachment
);
1277 void wxControlPoint::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
1279 m_shape
->GetEventHandler()->OnSizingEndDragLeft(this, x
, y
, keys
, attachment
);
1282 int wxControlPoint::GetNumberOfAttachments() const
1287 bool wxControlPoint::GetAttachmentPosition(int attachment
, double *x
, double *y
,
1288 int nth
, int no_arcs
, wxLineShape
*line
)
1290 *x
= m_xpos
; *y
= m_ypos
;
1294 // Control points ('handles') redirect control to the actual shape, to make it easier
1295 // to override sizing behaviour.
1296 void wxShape::OnSizingDragLeft(wxControlPoint
* pt
, bool draw
, double x
, double y
, int keys
, int attachment
)
1300 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1302 wxClientDC
dc(GetCanvas());
1303 GetCanvas()->PrepareDC(dc
);
1305 dc
.SetLogicalFunction(wxXOR
);
1307 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1308 dc
.SetPen(dottedPen
);
1309 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1311 if (this->GetCentreResize())
1313 // Maintain the same centre point.
1314 double new_width
= (double)(2.0*fabs(x
- this->GetX()));
1315 double new_height
= (double)(2.0*fabs(y
- this->GetY()));
1317 // Constrain sizing according to what control point you're dragging
1318 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1320 if (GetMaintainAspectRatio())
1322 new_height
= bound_y
*(new_width
/bound_x
);
1325 new_height
= bound_y
;
1327 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1329 if (GetMaintainAspectRatio())
1331 new_width
= bound_x
*(new_height
/bound_y
);
1334 new_width
= bound_x
;
1336 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& (keys
& KEY_SHIFT
))
1337 new_height
= bound_y
*(new_width
/bound_x
);
1339 if (this->GetFixedWidth())
1340 new_width
= bound_x
;
1342 if (this->GetFixedHeight())
1343 new_height
= bound_y
;
1345 pt
->sm_controlPointDragEndWidth
= new_width
;
1346 pt
->sm_controlPointDragEndHeight
= new_height
;
1348 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1349 new_width
, new_height
);
1353 // Don't maintain the same centre point!
1354 double newX1
= wxMin(pt
->sm_controlPointDragStartX
, x
);
1355 double newY1
= wxMin(pt
->sm_controlPointDragStartY
, y
);
1356 double newX2
= wxMax(pt
->sm_controlPointDragStartX
, x
);
1357 double newY2
= wxMax(pt
->sm_controlPointDragStartY
, y
);
1358 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1360 newY1
= pt
->sm_controlPointDragStartY
;
1361 newY2
= newY1
+ pt
->sm_controlPointDragStartHeight
;
1363 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1365 newX1
= pt
->sm_controlPointDragStartX
;
1366 newX2
= newX1
+ pt
->sm_controlPointDragStartWidth
;
1368 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& ((keys
& KEY_SHIFT
) || GetMaintainAspectRatio()))
1370 double newH
= (double)((newX2
- newX1
)*(pt
->sm_controlPointDragStartHeight
/pt
->sm_controlPointDragStartWidth
));
1371 if (GetY() > pt
->sm_controlPointDragStartY
)
1372 newY2
= (double)(newY1
+ newH
);
1374 newY1
= (double)(newY2
- newH
);
1376 double newWidth
= (double)(newX2
- newX1
);
1377 double newHeight
= (double)(newY2
- newY1
);
1379 if (pt
->m_type
== CONTROL_POINT_VERTICAL
&& GetMaintainAspectRatio())
1381 newWidth
= bound_x
* (newHeight
/bound_y
) ;
1384 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
&& GetMaintainAspectRatio())
1386 newHeight
= bound_y
* (newWidth
/bound_x
) ;
1389 pt
->sm_controlPointDragPosX
= (double)(newX1
+ (newWidth
/2.0));
1390 pt
->sm_controlPointDragPosY
= (double)(newY1
+ (newHeight
/2.0));
1391 if (this->GetFixedWidth())
1394 if (this->GetFixedHeight())
1395 newHeight
= bound_y
;
1397 pt
->sm_controlPointDragEndWidth
= newWidth
;
1398 pt
->sm_controlPointDragEndHeight
= newHeight
;
1399 this->GetEventHandler()->OnDrawOutline(dc
, pt
->sm_controlPointDragPosX
, pt
->sm_controlPointDragPosY
, newWidth
, newHeight
);
1403 void wxShape::OnSizingBeginDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int attachment
)
1405 m_canvas
->CaptureMouse();
1407 wxClientDC
dc(GetCanvas());
1408 GetCanvas()->PrepareDC(dc
);
1410 if (pt->m_eraseObject)
1414 dc
.SetLogicalFunction(wxXOR
);
1418 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1420 // Choose the 'opposite corner' of the object as the stationary
1421 // point in case this is non-centring resizing.
1422 if (pt
->GetX() < this->GetX())
1423 pt
->sm_controlPointDragStartX
= (double)(this->GetX() + (bound_x
/2.0));
1425 pt
->sm_controlPointDragStartX
= (double)(this->GetX() - (bound_x
/2.0));
1427 if (pt
->GetY() < this->GetY())
1428 pt
->sm_controlPointDragStartY
= (double)(this->GetY() + (bound_y
/2.0));
1430 pt
->sm_controlPointDragStartY
= (double)(this->GetY() - (bound_y
/2.0));
1432 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1433 pt
->sm_controlPointDragStartY
= (double)(this->GetY() - (bound_y
/2.0));
1434 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1435 pt
->sm_controlPointDragStartX
= (double)(this->GetX() - (bound_x
/2.0));
1437 // We may require the old width and height.
1438 pt
->sm_controlPointDragStartWidth
= bound_x
;
1439 pt
->sm_controlPointDragStartHeight
= bound_y
;
1441 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1442 dc
.SetPen(dottedPen
);
1443 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1445 if (this->GetCentreResize())
1447 double new_width
= (double)(2.0*fabs(x
- this->GetX()));
1448 double new_height
= (double)(2.0*fabs(y
- this->GetY()));
1450 // Constrain sizing according to what control point you're dragging
1451 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1453 if (GetMaintainAspectRatio())
1455 new_height
= bound_y
*(new_width
/bound_x
);
1458 new_height
= bound_y
;
1460 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1462 if (GetMaintainAspectRatio())
1464 new_width
= bound_x
*(new_height
/bound_y
);
1467 new_width
= bound_x
;
1469 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& (keys
& KEY_SHIFT
))
1470 new_height
= bound_y
*(new_width
/bound_x
);
1472 if (this->GetFixedWidth())
1473 new_width
= bound_x
;
1475 if (this->GetFixedHeight())
1476 new_height
= bound_y
;
1478 pt
->sm_controlPointDragEndWidth
= new_width
;
1479 pt
->sm_controlPointDragEndHeight
= new_height
;
1480 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1481 new_width
, new_height
);
1485 // Don't maintain the same centre point!
1486 double newX1
= wxMin(pt
->sm_controlPointDragStartX
, x
);
1487 double newY1
= wxMin(pt
->sm_controlPointDragStartY
, y
);
1488 double newX2
= wxMax(pt
->sm_controlPointDragStartX
, x
);
1489 double newY2
= wxMax(pt
->sm_controlPointDragStartY
, y
);
1490 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1492 newY1
= pt
->sm_controlPointDragStartY
;
1493 newY2
= newY1
+ pt
->sm_controlPointDragStartHeight
;
1495 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1497 newX1
= pt
->sm_controlPointDragStartX
;
1498 newX2
= newX1
+ pt
->sm_controlPointDragStartWidth
;
1500 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& ((keys
& KEY_SHIFT
) || GetMaintainAspectRatio()))
1502 double newH
= (double)((newX2
- newX1
)*(pt
->sm_controlPointDragStartHeight
/pt
->sm_controlPointDragStartWidth
));
1503 if (pt
->GetY() > pt
->sm_controlPointDragStartY
)
1504 newY2
= (double)(newY1
+ newH
);
1506 newY1
= (double)(newY2
- newH
);
1508 double newWidth
= (double)(newX2
- newX1
);
1509 double newHeight
= (double)(newY2
- newY1
);
1511 if (pt
->m_type
== CONTROL_POINT_VERTICAL
&& GetMaintainAspectRatio())
1513 newWidth
= bound_x
* (newHeight
/bound_y
) ;
1516 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
&& GetMaintainAspectRatio())
1518 newHeight
= bound_y
* (newWidth
/bound_x
) ;
1521 pt
->sm_controlPointDragPosX
= (double)(newX1
+ (newWidth
/2.0));
1522 pt
->sm_controlPointDragPosY
= (double)(newY1
+ (newHeight
/2.0));
1523 if (this->GetFixedWidth())
1526 if (this->GetFixedHeight())
1527 newHeight
= bound_y
;
1529 pt
->sm_controlPointDragEndWidth
= newWidth
;
1530 pt
->sm_controlPointDragEndHeight
= newHeight
;
1531 this->GetEventHandler()->OnDrawOutline(dc
, pt
->sm_controlPointDragPosX
, pt
->sm_controlPointDragPosY
, newWidth
, newHeight
);
1535 void wxShape::OnSizingEndDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int attachment
)
1537 wxClientDC
dc(GetCanvas());
1538 GetCanvas()->PrepareDC(dc
);
1540 m_canvas
->ReleaseMouse();
1541 dc
.SetLogicalFunction(wxCOPY
);
1543 this->ResetControlPoints();
1547 if (!pt->m_eraseObject)
1551 this->SetSize(pt
->sm_controlPointDragEndWidth
, pt
->sm_controlPointDragEndHeight
);
1553 // The next operation could destroy this control point (it does for label objects,
1554 // via formatting the text), so save all values we're going to use, or
1555 // we'll be accessing garbage.
1556 wxShape
*theObject
= this;
1557 wxShapeCanvas
*theCanvas
= m_canvas
;
1558 bool eraseIt
= pt
->m_eraseObject
;
1560 if (theObject
->GetCentreResize())
1561 theObject
->Move(dc
, theObject
->GetX(), theObject
->GetY());
1563 theObject
->Move(dc
, pt
->sm_controlPointDragPosX
, pt
->sm_controlPointDragPosY
);
1567 theObject->Show(TRUE);
1570 // Recursively redraw links if we have a composite.
1571 if (theObject
->GetChildren().Number() > 0)
1572 theObject
->DrawLinks(dc
, -1, TRUE
);
1574 double width
, height
;
1575 theObject
->GetBoundingBoxMax(&width
, &height
);
1576 theObject
->GetEventHandler()->OnEndSize(width
, height
);
1578 if (!theCanvas
->GetQuickEditMode() && eraseIt
) theCanvas
->Redraw(dc
);
1583 // Polygon control points
1585 IMPLEMENT_DYNAMIC_CLASS(wxPolygonControlPoint
, wxControlPoint
)
1587 wxPolygonControlPoint::wxPolygonControlPoint(wxShapeCanvas
*theCanvas
, wxShape
*object
, double size
,
1588 wxRealPoint
*vertex
, double the_xoffset
, double the_yoffset
):
1589 wxControlPoint(theCanvas
, object
, size
, the_xoffset
, the_yoffset
, 0)
1591 m_polygonVertex
= vertex
;
1592 m_originalDistance
= 0.0;
1595 wxPolygonControlPoint::~wxPolygonControlPoint()
1599 // Calculate what new size would be, at end of resize
1600 void wxPolygonControlPoint::CalculateNewSize(double x
, double y
)
1604 GetShape()->GetBoundingBoxMin(&bound_x
, &bound_y
);
1606 double dist
= (double)sqrt((x
- m_shape
->GetX())*(x
- m_shape
->GetX()) +
1607 (y
- m_shape
->GetY())*(y
- m_shape
->GetY()));
1609 m_newSize
.x
= (double)(dist
/this->m_originalDistance
)*this->m_originalSize
.x
;
1610 m_newSize
.y
= (double)(dist
/this->m_originalDistance
)*this->m_originalSize
.y
;
1614 // Implement resizing polygon or moving the vertex.
1615 void wxPolygonControlPoint::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
1617 m_shape
->GetEventHandler()->OnSizingDragLeft(this, draw
, x
, y
, keys
, attachment
);
1620 void wxPolygonControlPoint::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
1622 m_shape
->GetEventHandler()->OnSizingBeginDragLeft(this, x
, y
, keys
, attachment
);
1625 void wxPolygonControlPoint::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
1627 m_shape
->GetEventHandler()->OnSizingEndDragLeft(this, x
, y
, keys
, attachment
);
1630 // Control points ('handles') redirect control to the actual shape, to make it easier
1631 // to override sizing behaviour.
1632 void wxPolygonShape::OnSizingDragLeft(wxControlPoint
* pt
, bool draw
, double x
, double y
, int keys
, int attachment
)
1634 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
1636 wxClientDC
dc(GetCanvas());
1637 GetCanvas()->PrepareDC(dc
);
1639 dc
.SetLogicalFunction(wxXOR
);
1641 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1642 dc
.SetPen(dottedPen
);
1643 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1645 if (0) // keys & KEY_CTRL)
1647 // TODO: mend this code. Currently we rely on altering the
1648 // actual points, but we should assume we're not, as per
1649 // the normal sizing case.
1650 m_canvas
->Snap(&x
, &y
);
1653 ppt
->m_polygonVertex
->x
= x
- this->GetX();
1654 ppt
->m_polygonVertex
->y
= y
- this->GetY();
1657 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1658 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1662 ppt
->CalculateNewSize(x
, y
);
1665 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1666 ppt
->GetNewSize().x
, ppt
->GetNewSize().y
);
1669 void wxPolygonShape::OnSizingBeginDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int attachment
)
1671 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
1673 wxClientDC
dc(GetCanvas());
1674 GetCanvas()->PrepareDC(dc
);
1678 dc
.SetLogicalFunction(wxXOR
);
1682 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1684 double dist
= (double)sqrt((x
- this->GetX())*(x
- this->GetX()) +
1685 (y
- this->GetY())*(y
- this->GetY()));
1686 ppt
->m_originalDistance
= dist
;
1687 ppt
->m_originalSize
.x
= bound_x
;
1688 ppt
->m_originalSize
.y
= bound_y
;
1690 if (ppt
->m_originalDistance
== 0.0) ppt
->m_originalDistance
= (double) 0.0001;
1692 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1693 dc
.SetPen(dottedPen
);
1694 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1696 if (0) // keys & KEY_CTRL)
1698 // TODO: mend this code. Currently we rely on altering the
1699 // actual points, but we should assume we're not, as per
1700 // the normal sizing case.
1701 m_canvas
->Snap(&x
, &y
);
1704 ppt
->m_polygonVertex
->x
= x
- this->GetX();
1705 ppt
->m_polygonVertex
->y
= y
- this->GetY();
1708 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1709 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1713 ppt
->CalculateNewSize(x
, y
);
1716 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1717 ppt
->GetNewSize().x
, ppt
->GetNewSize().y
);
1719 m_canvas
->CaptureMouse();
1722 void wxPolygonShape::OnSizingEndDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int attachment
)
1724 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
1726 wxClientDC
dc(GetCanvas());
1727 GetCanvas()->PrepareDC(dc
);
1729 m_canvas
->ReleaseMouse();
1730 dc
.SetLogicalFunction(wxCOPY
);
1732 // If we're changing shape, must reset the original points
1733 if (keys
& KEY_CTRL
)
1735 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1736 ((wxPolygonShape
*)this)->UpdateOriginalPoints();
1740 SetSize(ppt
->GetNewSize().x
, ppt
->GetNewSize().y
);
1743 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1744 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1747 this->ResetControlPoints();
1748 this->Move(dc
, this->GetX(), this->GetY());
1749 if (!m_canvas
->GetQuickEditMode()) m_canvas
->Redraw(dc
);
1756 IMPLEMENT_DYNAMIC_CLASS(wxShapeRegion
, wxObject
)
1758 wxShapeRegion::wxShapeRegion()
1761 m_font
= g_oglNormalFont
;
1769 m_regionProportionX
= -1.0;
1770 m_regionProportionY
= -1.0;
1771 m_formatMode
= FORMAT_CENTRE_HORIZ
| FORMAT_CENTRE_VERT
;
1773 m_textColour
= "BLACK";
1774 m_penColour
= "BLACK";
1775 m_penStyle
= wxSOLID
;
1776 m_actualColourObject
= NULL
;
1777 m_actualPenObject
= NULL
;
1780 wxShapeRegion::wxShapeRegion(wxShapeRegion
& region
)
1782 m_regionText
= region
.m_regionText
;
1783 m_regionName
= region
.m_regionName
;
1784 m_textColour
= region
.m_textColour
;
1786 m_font
= region
.m_font
;
1787 m_minHeight
= region
.m_minHeight
;
1788 m_minWidth
= region
.m_minWidth
;
1789 m_width
= region
.m_width
;
1790 m_height
= region
.m_height
;
1794 m_regionProportionX
= region
.m_regionProportionX
;
1795 m_regionProportionY
= region
.m_regionProportionY
;
1796 m_formatMode
= region
.m_formatMode
;
1797 m_actualColourObject
= NULL
;
1798 m_actualPenObject
= NULL
;
1799 m_penStyle
= region
.m_penStyle
;
1800 m_penColour
= region
.m_penColour
;
1803 wxNode
*node
= region
.m_formattedText
.First();
1806 wxShapeTextLine
*line
= (wxShapeTextLine
*)node
->Data();
1807 wxShapeTextLine
*new_line
=
1808 new wxShapeTextLine(line
->GetX(), line
->GetY(), line
->GetText());
1809 m_formattedText
.Append(new_line
);
1810 node
= node
->Next();
1814 wxShapeRegion::~wxShapeRegion()
1819 void wxShapeRegion::ClearText()
1821 wxNode
*node
= m_formattedText
.First();
1824 wxShapeTextLine
*line
= (wxShapeTextLine
*)node
->Data();
1825 wxNode
*next
= node
->Next();
1832 void wxShapeRegion::SetFont(wxFont
*f
)
1837 void wxShapeRegion::SetMinSize(double w
, double h
)
1843 void wxShapeRegion::SetSize(double w
, double h
)
1849 void wxShapeRegion::SetPosition(double xp
, double yp
)
1855 void wxShapeRegion::SetProportions(double xp
, double yp
)
1857 m_regionProportionX
= xp
;
1858 m_regionProportionY
= yp
;
1861 void wxShapeRegion::SetFormatMode(int mode
)
1863 m_formatMode
= mode
;
1866 void wxShapeRegion::SetColour(const wxString
& col
)
1869 m_actualColourObject
= NULL
;
1872 wxColour
*wxShapeRegion::GetActualColourObject()
1874 if (!m_actualColourObject
)
1875 m_actualColourObject
= wxTheColourDatabase
->FindColour(GetColour());
1876 if (!m_actualColourObject
)
1877 m_actualColourObject
= wxBLACK
;
1878 return m_actualColourObject
;
1881 void wxShapeRegion::SetPenColour(const wxString
& col
)
1884 m_actualPenObject
= NULL
;
1887 // Returns NULL if the pen is invisible
1888 // (different to pen being transparent; indicates that
1889 // region boundary should not be drawn.)
1890 wxPen
*wxShapeRegion::GetActualPen()
1892 if (m_actualPenObject
)
1893 return m_actualPenObject
;
1895 if (!m_penColour
) return NULL
;
1896 if (m_penColour
== "Invisible")
1898 m_actualPenObject
= wxThePenList
->FindOrCreatePen(m_penColour
, 1, m_penStyle
);
1899 return m_actualPenObject
;