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 double maxX, maxY, minX, minY;
564 GetBoundingBoxMax(&maxX, &maxY);
565 GetBoundingBoxMin(&minX, &minY);
567 double widthMin = (double)(minX + CONTROL_POINT_SIZE + 2);
568 double heightMin = (double)(minY + CONTROL_POINT_SIZE + 2);
570 // Offsets from main object
571 double top = (double)(- (heightMin / 2.0));
572 double bottom = (double)(heightMin / 2.0 + (maxY - minY));
573 double left = (double)(- (widthMin / 2.0));
574 double right = (double)(widthMin / 2.0 + (maxX - minX));
576 wxControlPoint *control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, top,
577 CONTROL_POINT_DIAGONAL);
578 m_canvas->AddShape(control);
579 m_controlPoints.Append(control);
581 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, 0, top,
582 CONTROL_POINT_VERTICAL);
583 m_canvas->AddShape(control);
584 m_controlPoints.Append(control);
586 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, top,
587 CONTROL_POINT_DIAGONAL);
588 m_canvas->AddShape(control);
589 m_controlPoints.Append(control);
591 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, 0,
592 CONTROL_POINT_HORIZONTAL);
593 m_canvas->AddShape(control);
594 m_controlPoints.Append(control);
596 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, bottom,
597 CONTROL_POINT_DIAGONAL);
598 m_canvas->AddShape(control);
599 m_controlPoints.Append(control);
601 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, 0, bottom,
602 CONTROL_POINT_VERTICAL);
603 m_canvas->AddShape(control);
604 m_controlPoints.Append(control);
606 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, bottom,
607 CONTROL_POINT_DIAGONAL);
608 m_canvas->AddShape(control);
609 m_controlPoints.Append(control);
611 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, 0,
612 CONTROL_POINT_HORIZONTAL);
613 m_canvas->AddShape(control);
614 m_controlPoints.Append(control);
618 void wxPolygonShape::ResetControlPoints()
620 wxNode
*node
= m_points
->First();
621 wxNode
*controlPointNode
= m_controlPoints
.First();
622 while (node
&& controlPointNode
)
624 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
625 wxPolygonControlPoint
*controlPoint
= (wxPolygonControlPoint
*)controlPointNode
->Data();
627 controlPoint
->m_xoffset
= point
->x
;
628 controlPoint
->m_yoffset
= point
->y
;
629 controlPoint
->m_polygonVertex
= point
;
632 controlPointNode
= controlPointNode
->Next();
636 if (m_controlPoints.Number() < 1)
639 double maxX, maxY, minX, minY;
641 GetBoundingBoxMax(&maxX, &maxY);
642 GetBoundingBoxMin(&minX, &minY);
644 double widthMin = (double)(minX + CONTROL_POINT_SIZE + 2);
645 double heightMin = (double)(minY + CONTROL_POINT_SIZE + 2);
647 // Offsets from main object
648 double top = (double)(- (heightMin / 2.0));
649 double bottom = (double)(heightMin / 2.0 + (maxY - minY));
650 double left = (double)(- (widthMin / 2.0));
651 double right = (double)(widthMin / 2.0 + (maxX - minX));
653 wxNode *node = m_controlPoints.First();
654 wxControlPoint *control = (wxControlPoint *)node->Data();
655 control->xoffset = left; control->yoffset = top;
657 node = node->Next(); control = (wxControlPoint *)node->Data();
658 control->xoffset = 0; control->yoffset = top;
660 node = node->Next(); control = (wxControlPoint *)node->Data();
661 control->xoffset = right; control->yoffset = top;
663 node = node->Next(); control = (wxControlPoint *)node->Data();
664 control->xoffset = right; control->yoffset = 0;
666 node = node->Next(); control = (wxControlPoint *)node->Data();
667 control->xoffset = right; control->yoffset = bottom;
669 node = node->Next(); control = (wxControlPoint *)node->Data();
670 control->xoffset = 0; control->yoffset = bottom;
672 node = node->Next(); control = (wxControlPoint *)node->Data();
673 control->xoffset = left; control->yoffset = bottom;
675 node = node->Next(); control = (wxControlPoint *)node->Data();
676 control->xoffset = left; control->yoffset = 0;
682 void wxPolygonShape::WritePrologAttributes(wxExpr
*clause
)
684 wxShape::WritePrologAttributes(clause
);
686 clause
->AddAttributeValue("x", m_xpos
);
687 clause
->AddAttributeValue("y", m_ypos
);
689 // Make a list of lists for the coordinates
690 wxExpr
*list
= new wxExpr(PrologList
);
691 wxNode
*node
= m_points
->First();
694 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
695 wxExpr
*point_list
= new wxExpr(PrologList
);
696 wxExpr
*x_expr
= new wxExpr((double)point
->x
);
697 wxExpr
*y_expr
= new wxExpr((double)point
->y
);
699 point_list
->Append(x_expr
);
700 point_list
->Append(y_expr
);
701 list
->Append(point_list
);
705 clause
->AddAttributeValue("points", list
);
707 // Save the original (unscaled) points
708 list
= new wxExpr(PrologList
);
709 node
= m_originalPoints
->First();
712 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
713 wxExpr
*point_list
= new wxExpr(PrologList
);
714 wxExpr
*x_expr
= new wxExpr((double) point
->x
);
715 wxExpr
*y_expr
= new wxExpr((double) point
->y
);
716 point_list
->Append(x_expr
);
717 point_list
->Append(y_expr
);
718 list
->Append(point_list
);
722 clause
->AddAttributeValue("m_originalPoints", list
);
725 void wxPolygonShape::ReadPrologAttributes(wxExpr
*clause
)
727 wxShape::ReadPrologAttributes(clause
);
729 // Read a list of lists
730 m_points
= new wxList
;
731 m_originalPoints
= new wxList
;
733 wxExpr
*points_list
= NULL
;
734 clause
->AssignAttributeValue("points", &points_list
);
736 // If no points_list, don't crash!! Assume a diamond instead.
737 double the_height
= 100.0;
738 double the_width
= 100.0;
741 wxRealPoint
*point
= new wxRealPoint(0.0, (-the_height
/2));
742 m_points
->Append((wxObject
*) point
);
744 point
= new wxRealPoint((the_width
/2), 0.0);
745 m_points
->Append((wxObject
*) point
);
747 point
= new wxRealPoint(0.0, (the_height
/2));
748 m_points
->Append((wxObject
*) point
);
750 point
= new wxRealPoint((-the_width
/2), 0.0);
751 m_points
->Append((wxObject
*) point
);
753 point
= new wxRealPoint(0.0, (-the_height
/2));
754 m_points
->Append((wxObject
*) point
);
758 wxExpr
*node
= points_list
->value
.first
;
762 wxExpr
*xexpr
= node
->value
.first
;
763 long x
= xexpr
->IntegerValue();
765 wxExpr
*yexpr
= xexpr
->next
;
766 long y
= yexpr
->IntegerValue();
768 wxRealPoint
*point
= new wxRealPoint((double)x
, (double)y
);
769 m_points
->Append((wxObject
*) point
);
776 clause
->AssignAttributeValue("m_originalPoints", &points_list
);
778 // If no points_list, don't crash!! Assume a diamond instead.
781 wxRealPoint
*point
= new wxRealPoint(0.0, (-the_height
/2));
782 m_originalPoints
->Append((wxObject
*) point
);
784 point
= new wxRealPoint((the_width
/2), 0.0);
785 m_originalPoints
->Append((wxObject
*) point
);
787 point
= new wxRealPoint(0.0, (the_height
/2));
788 m_originalPoints
->Append((wxObject
*) point
);
790 point
= new wxRealPoint((-the_width
/2), 0.0);
791 m_originalPoints
->Append((wxObject
*) point
);
793 point
= new wxRealPoint(0.0, (-the_height
/2));
794 m_originalPoints
->Append((wxObject
*) point
);
796 m_originalWidth
= the_width
;
797 m_originalHeight
= the_height
;
801 wxExpr
*node
= points_list
->value
.first
;
804 double max_x
= -1000;
805 double max_y
= -1000;
808 wxExpr
*xexpr
= node
->value
.first
;
809 long x
= xexpr
->IntegerValue();
811 wxExpr
*yexpr
= xexpr
->next
;
812 long y
= yexpr
->IntegerValue();
814 wxRealPoint
*point
= new wxRealPoint((double)x
, (double)y
);
815 m_originalPoints
->Append((wxObject
*) point
);
828 m_originalWidth
= max_x
- min_x
;
829 m_originalHeight
= max_y
- min_y
;
832 CalculateBoundingBox();
836 void wxPolygonShape::Copy(wxShape
& copy
)
840 wxASSERT( copy
.IsKindOf(CLASSINFO(wxPolygonShape
)) );
842 wxPolygonShape
& polyCopy
= (wxPolygonShape
&) copy
;
844 polyCopy
.ClearPoints();
846 polyCopy
.m_points
= new wxList
;
847 polyCopy
.m_originalPoints
= new wxList
;
849 wxNode
*node
= m_points
->First();
852 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
853 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
854 polyCopy
.m_points
->Append((wxObject
*) new_point
);
857 node
= m_originalPoints
->First();
860 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
861 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
862 polyCopy
.m_originalPoints
->Append((wxObject
*) new_point
);
865 polyCopy
.m_boundWidth
= m_boundWidth
;
866 polyCopy
.m_boundHeight
= m_boundHeight
;
867 polyCopy
.m_originalWidth
= m_originalWidth
;
868 polyCopy
.m_originalHeight
= m_originalHeight
;
871 int wxPolygonShape::GetNumberOfAttachments()
873 int maxN
= (m_points
? (m_points
->Number() - 1) : 0);
874 wxNode
*node
= m_attachmentPoints
.First();
877 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
878 if (point
->m_id
> maxN
)
885 bool wxPolygonShape::GetAttachmentPosition(int attachment
, double *x
, double *y
,
886 int nth
, int no_arcs
, wxLineShape
*line
)
888 if (m_attachmentMode
&& m_points
&& attachment
< m_points
->Number())
890 wxRealPoint
*point
= (wxRealPoint
*)m_points
->Nth(attachment
)->Data();
891 *x
= point
->x
+ m_xpos
;
892 *y
= point
->y
+ m_ypos
;
896 { return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
); }
899 bool wxPolygonShape::AttachmentIsValid(int attachment
)
904 if ((attachment
>= 0) && (attachment
< m_points
->Number()))
907 wxNode
*node
= m_attachmentPoints
.First();
910 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
911 if (point
->m_id
== attachment
)
920 IMPLEMENT_DYNAMIC_CLASS(wxRectangleShape
, wxShape
)
922 wxRectangleShape::wxRectangleShape(double w
, double h
)
924 m_width
= w
; m_height
= h
; m_cornerRadius
= 0.0;
925 SetDefaultRegionSize();
928 void wxRectangleShape::OnDraw(wxDC
& dc
)
930 double x1
= (double)(m_xpos
- m_width
/2.0);
931 double y1
= (double)(m_ypos
- m_height
/2.0);
933 if (m_shadowMode
!= SHADOW_NONE
)
936 dc
.SetBrush(m_shadowBrush
);
937 dc
.SetPen(g_oglTransparentPen
);
939 if (m_cornerRadius
!= 0.0)
940 dc
.DrawRoundedRectangle(WXROUND(x1
+ m_shadowOffsetX
), WXROUND(y1
+ m_shadowOffsetY
),
941 WXROUND(m_width
), WXROUND(m_height
), m_cornerRadius
);
943 dc
.DrawRectangle(WXROUND(x1
+ m_shadowOffsetX
), WXROUND(y1
+ m_shadowOffsetY
), WXROUND(m_width
), WXROUND(m_height
));
948 if (m_pen
->GetWidth() == 0)
949 dc
.SetPen(g_oglTransparentPen
);
954 dc
.SetBrush(m_brush
);
956 if (m_cornerRadius
!= 0.0)
957 dc
.DrawRoundedRectangle(WXROUND(x1
), WXROUND(y1
), WXROUND(m_width
), WXROUND(m_height
), m_cornerRadius
);
959 dc
.DrawRectangle(WXROUND(x1
), WXROUND(y1
), WXROUND(m_width
), WXROUND(m_height
));
962 void wxRectangleShape::GetBoundingBoxMin(double *the_width
, double *the_height
)
964 *the_width
= m_width
;
965 *the_height
= m_height
;
968 void wxRectangleShape::SetSize(double x
, double y
, bool recursive
)
970 SetAttachmentSize(x
, y
);
971 m_width
= (double)wxMax(x
, 1.0);
972 m_height
= (double)wxMax(y
, 1.0);
973 SetDefaultRegionSize();
976 void wxRectangleShape::SetCornerRadius(double rad
)
978 m_cornerRadius
= rad
;
981 // Assume (x1, y1) is centre of box (most generally, line end at box)
982 bool wxRectangleShape::GetPerimeterPoint(double x1
, double y1
,
983 double x2
, double y2
,
984 double *x3
, double *y3
)
986 double bound_x
, bound_y
;
987 GetBoundingBoxMax(&bound_x
, &bound_y
);
988 oglFindEndForBox(bound_x
, bound_y
, m_xpos
, m_ypos
, x2
, y2
, x3
, y3
);
994 void wxRectangleShape::WritePrologAttributes(wxExpr
*clause
)
996 wxShape::WritePrologAttributes(clause
);
997 clause
->AddAttributeValue("x", m_xpos
);
998 clause
->AddAttributeValue("y", m_ypos
);
1000 clause
->AddAttributeValue("width", m_width
);
1001 clause
->AddAttributeValue("height", m_height
);
1002 if (m_cornerRadius
!= 0.0)
1003 clause
->AddAttributeValue("corner", m_cornerRadius
);
1006 void wxRectangleShape::ReadPrologAttributes(wxExpr
*clause
)
1008 wxShape::ReadPrologAttributes(clause
);
1009 clause
->AssignAttributeValue("width", &m_width
);
1010 clause
->AssignAttributeValue("height", &m_height
);
1011 clause
->AssignAttributeValue("corner", &m_cornerRadius
);
1013 // In case we're reading an old file, set the region's size
1014 if (m_regions
.Number() == 1)
1016 wxShapeRegion
*region
= (wxShapeRegion
*)m_regions
.First()->Data();
1017 region
->SetSize(m_width
, m_height
);
1022 void wxRectangleShape::Copy(wxShape
& copy
)
1024 wxShape::Copy(copy
);
1026 wxASSERT( copy
.IsKindOf(CLASSINFO(wxRectangleShape
)) );
1028 wxRectangleShape
& rectCopy
= (wxRectangleShape
&) copy
;
1029 rectCopy
.m_width
= m_width
;
1030 rectCopy
.m_height
= m_height
;
1031 rectCopy
.m_cornerRadius
= m_cornerRadius
;
1034 int wxRectangleShape::GetNumberOfAttachments()
1036 return wxShape::GetNumberOfAttachments();
1040 // There are 4 attachment points on a rectangle - 0 = top, 1 = right, 2 = bottom,
1042 bool wxRectangleShape::GetAttachmentPosition(int attachment
, double *x
, double *y
,
1043 int nth
, int no_arcs
, wxLineShape
*line
)
1045 if (m_attachmentMode
)
1047 double top
= (double)(m_ypos
+ m_height
/2.0);
1048 double bottom
= (double)(m_ypos
- m_height
/2.0);
1049 double left
= (double)(m_xpos
- m_width
/2.0);
1050 double right
= (double)(m_xpos
+ m_width
/2.0);
1052 bool isEnd
= (line
&& line
->IsEnd(this));
1059 wxRealPoint pt
= CalcSimpleAttachment(wxRealPoint(left
, bottom
), wxRealPoint(right
, bottom
),
1060 nth
, no_arcs
, line
);
1062 *x
= pt
.x
; *y
= pt
.y
;
1067 wxRealPoint pt
= CalcSimpleAttachment(wxRealPoint(right
, bottom
), wxRealPoint(right
, top
),
1068 nth
, no_arcs
, line
);
1070 *x
= pt
.x
; *y
= pt
.y
;
1075 wxRealPoint pt
= CalcSimpleAttachment(wxRealPoint(left
, top
), wxRealPoint(right
, top
),
1076 nth
, no_arcs
, line
);
1078 *x
= pt
.x
; *y
= pt
.y
;
1083 wxRealPoint pt
= CalcSimpleAttachment(wxRealPoint(left
, bottom
), wxRealPoint(left
, top
),
1084 nth
, no_arcs
, line
);
1086 *x
= pt
.x
; *y
= pt
.y
;
1091 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
1102 if (m_spaceAttachments
)
1104 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
1106 // Align line according to the next handle along
1107 wxRealPoint
*point
= line
->GetNextControlPoint(this);
1108 if (point
->x
< left
)
1110 else if (point
->x
> right
)
1116 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
1126 if (m_spaceAttachments
)
1128 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
1130 // Align line according to the next handle along
1131 wxRealPoint
*point
= line
->GetNextControlPoint(this);
1132 if (point
->y
< bottom
)
1134 else if (point
->y
> top
)
1140 *y
= bottom
+ (nth
+ 1)*m_height
/(no_arcs
+ 1);
1147 if (m_spaceAttachments
)
1149 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
1151 // Align line according to the next handle along
1152 wxRealPoint
*point
= line
->GetNextControlPoint(this);
1153 if (point
->x
< left
)
1155 else if (point
->x
> right
)
1161 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
1170 if (m_spaceAttachments
)
1172 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
1174 // Align line according to the next handle along
1175 wxRealPoint
*point
= line
->GetNextControlPoint(this);
1176 if (point
->y
< bottom
)
1178 else if (point
->y
> top
)
1184 *y
= bottom
+ (nth
+ 1)*m_height
/(no_arcs
+ 1);
1191 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
1199 { *x
= m_xpos
; *y
= m_ypos
; return TRUE
; }
1202 // Text object (no box)
1204 IMPLEMENT_DYNAMIC_CLASS(wxTextShape
, wxRectangleShape
)
1206 wxTextShape::wxTextShape(double width
, double height
):
1207 wxRectangleShape(width
, height
)
1211 void wxTextShape::OnDraw(wxDC
& dc
)
1215 void wxTextShape::Copy(wxShape
& copy
)
1217 wxRectangleShape::Copy(copy
);
1221 void wxTextShape::WritePrologAttributes(wxExpr
*clause
)
1223 wxRectangleShape::WritePrologAttributes(clause
);
1229 IMPLEMENT_DYNAMIC_CLASS(wxEllipseShape
, wxShape
)
1231 wxEllipseShape::wxEllipseShape(double w
, double h
)
1233 m_width
= w
; m_height
= h
;
1234 SetDefaultRegionSize();
1237 void wxEllipseShape::GetBoundingBoxMin(double *w
, double *h
)
1239 *w
= m_width
; *h
= m_height
;
1242 bool wxEllipseShape::GetPerimeterPoint(double x1
, double y1
,
1243 double x2
, double y2
,
1244 double *x3
, double *y3
)
1246 double bound_x
, bound_y
;
1247 GetBoundingBoxMax(&bound_x
, &bound_y
);
1249 // oglFindEndForBox(bound_x, bound_y, m_xpos, m_ypos, x2, y2, x3, y3);
1250 oglDrawArcToEllipse(m_xpos
, m_ypos
, bound_x
, bound_y
, x2
, y2
, x1
, y1
, x3
, y3
);
1255 void wxEllipseShape::OnDraw(wxDC
& dc
)
1257 if (m_shadowMode
!= SHADOW_NONE
)
1260 dc
.SetBrush(m_shadowBrush
);
1261 dc
.SetPen(g_oglTransparentPen
);
1262 dc
.DrawEllipse((m_xpos
- GetWidth()/2) + m_shadowOffsetX
,
1263 (m_ypos
- GetHeight()/2) + m_shadowOffsetY
,
1264 GetWidth(), GetHeight());
1269 if (m_pen
->GetWidth() == 0)
1270 dc
.SetPen(g_oglTransparentPen
);
1275 dc
.SetBrush(m_brush
);
1276 dc
.DrawEllipse((m_xpos
- GetWidth()/2), (m_ypos
- GetHeight()/2), GetWidth(), GetHeight());
1279 void wxEllipseShape::SetSize(double x
, double y
, bool recursive
)
1281 SetAttachmentSize(x
, y
);
1284 SetDefaultRegionSize();
1288 void wxEllipseShape::WritePrologAttributes(wxExpr
*clause
)
1290 wxShape::WritePrologAttributes(clause
);
1291 clause
->AddAttributeValue("x", m_xpos
);
1292 clause
->AddAttributeValue("y", m_ypos
);
1294 clause
->AddAttributeValue("width", m_width
);
1295 clause
->AddAttributeValue("height", m_height
);
1298 void wxEllipseShape::ReadPrologAttributes(wxExpr
*clause
)
1300 wxShape::ReadPrologAttributes(clause
);
1301 clause
->AssignAttributeValue("width", &m_width
);
1302 clause
->AssignAttributeValue("height", &m_height
);
1304 // In case we're reading an old file, set the region's size
1305 if (m_regions
.Number() == 1)
1307 wxShapeRegion
*region
= (wxShapeRegion
*)m_regions
.First()->Data();
1308 region
->SetSize(m_width
, m_height
);
1313 void wxEllipseShape::Copy(wxShape
& copy
)
1315 wxShape::Copy(copy
);
1317 wxASSERT( copy
.IsKindOf(CLASSINFO(wxEllipseShape
)) );
1319 wxEllipseShape
& ellipseCopy
= (wxEllipseShape
&) copy
;
1321 ellipseCopy
.m_width
= m_width
;
1322 ellipseCopy
.m_height
= m_height
;
1325 int wxEllipseShape::GetNumberOfAttachments()
1327 return wxShape::GetNumberOfAttachments();
1330 // There are 4 attachment points on an ellipse - 0 = top, 1 = right, 2 = bottom,
1332 bool wxEllipseShape::GetAttachmentPosition(int attachment
, double *x
, double *y
,
1333 int nth
, int no_arcs
, wxLineShape
*line
)
1335 if (m_attachmentMode
)
1337 double top
= (double)(m_ypos
+ m_height
/2.0);
1338 double bottom
= (double)(m_ypos
- m_height
/2.0);
1339 double left
= (double)(m_xpos
- m_width
/2.0);
1340 double right
= (double)(m_xpos
+ m_width
/2.0);
1345 if (m_spaceAttachments
)
1346 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
1349 // We now have the point on the bounding box: but get the point on the ellipse
1350 // by imagining a vertical line from (*x, m_ypos - m_height- 500) to (*x, m_ypos) intersecting
1352 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, *x
, (double)(m_ypos
-m_height
-500), *x
, m_ypos
, x
, y
);
1358 if (m_spaceAttachments
)
1359 *y
= bottom
+ (nth
+ 1)*m_height
/(no_arcs
+ 1);
1361 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, (double)(m_xpos
+m_width
+500), *y
, m_xpos
, *y
, x
, y
);
1366 if (m_spaceAttachments
)
1367 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
1370 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, *x
, (double)(m_ypos
+m_height
+500), *x
, m_ypos
, x
, y
);
1376 if (m_spaceAttachments
)
1377 *y
= bottom
+ (nth
+ 1)*m_height
/(no_arcs
+ 1);
1379 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, (double)(m_xpos
-m_width
-500), *y
, m_xpos
, *y
, x
, y
);
1384 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
1391 { *x
= m_xpos
; *y
= m_ypos
; return TRUE
; }
1396 IMPLEMENT_DYNAMIC_CLASS(wxCircleShape
, wxEllipseShape
)
1398 wxCircleShape::wxCircleShape(double diameter
):wxEllipseShape(diameter
, diameter
)
1402 void wxCircleShape::Copy(wxShape
& copy
)
1404 wxEllipseShape::Copy(copy
);
1407 bool wxCircleShape::GetPerimeterPoint(double x1
, double y1
,
1408 double x2
, double y2
,
1409 double *x3
, double *y3
)
1411 oglFindEndForCircle(m_width
/2,
1412 m_xpos
, m_ypos
, // Centre of circle
1413 x2
, y2
, // Other end of line
1421 double wxControlPoint::controlPointDragStartX
= 0.0;
1422 double wxControlPoint::controlPointDragStartY
= 0.0;
1423 double wxControlPoint::controlPointDragStartWidth
= 0.0;
1424 double wxControlPoint::controlPointDragStartHeight
= 0.0;
1425 double wxControlPoint::controlPointDragEndWidth
= 0.0;
1426 double wxControlPoint::controlPointDragEndHeight
= 0.0;
1427 double wxControlPoint::controlPointDragPosX
= 0.0;
1428 double wxControlPoint::controlPointDragPosY
= 0.0;
1430 IMPLEMENT_DYNAMIC_CLASS(wxControlPoint
, wxRectangleShape
)
1432 wxControlPoint::wxControlPoint(wxShapeCanvas
*theCanvas
, wxShape
*object
, double size
, double the_xoffset
, double the_yoffset
, int the_type
):wxRectangleShape(size
, size
)
1434 m_canvas
= theCanvas
;
1436 m_xoffset
= the_xoffset
;
1437 m_yoffset
= the_yoffset
;
1439 SetPen(g_oglBlackForegroundPen
);
1440 SetBrush(wxBLACK_BRUSH
);
1443 m_eraseObject
= TRUE
;
1446 wxControlPoint::~wxControlPoint()
1450 // Don't even attempt to draw any text - waste of time!
1451 void wxControlPoint::OnDrawContents(wxDC
& dc
)
1455 void wxControlPoint::OnDraw(wxDC
& dc
)
1457 m_xpos
= m_shape
->GetX() + m_xoffset
;
1458 m_ypos
= m_shape
->GetY() + m_yoffset
;
1459 wxRectangleShape::OnDraw(dc
);
1462 void wxControlPoint::OnErase(wxDC
& dc
)
1464 wxRectangleShape::OnErase(dc
);
1467 // Implement resizing of canvas object
1468 void wxControlPoint::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
1470 m_shape
->GetEventHandler()->OnSizingDragLeft(this, draw
, x
, y
, keys
, attachment
);
1473 void wxControlPoint::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
1475 m_shape
->GetEventHandler()->OnSizingBeginDragLeft(this, x
, y
, keys
, attachment
);
1478 void wxControlPoint::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
1480 m_shape
->GetEventHandler()->OnSizingEndDragLeft(this, x
, y
, keys
, attachment
);
1483 int wxControlPoint::GetNumberOfAttachments()
1488 bool wxControlPoint::GetAttachmentPosition(int attachment
, double *x
, double *y
,
1489 int nth
, int no_arcs
, wxLineShape
*line
)
1491 *x
= m_xpos
; *y
= m_ypos
;
1495 // Control points ('handles') redirect control to the actual shape, to make it easier
1496 // to override sizing behaviour.
1497 void wxShape::OnSizingDragLeft(wxControlPoint
* pt
, bool draw
, double x
, double y
, int keys
, int attachment
)
1501 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1503 wxClientDC
dc(GetCanvas());
1504 GetCanvas()->PrepareDC(dc
);
1506 dc
.SetLogicalFunction(wxXOR
);
1508 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1509 dc
.SetPen(dottedPen
);
1510 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1512 if (this->GetCentreResize())
1514 // Maintain the same centre point.
1515 double new_width
= (double)(2.0*fabs(x
- this->GetX()));
1516 double new_height
= (double)(2.0*fabs(y
- this->GetY()));
1518 // Constrain sizing according to what control point you're dragging
1519 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1520 new_height
= bound_y
;
1521 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1522 new_width
= bound_x
;
1523 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& (keys
& KEY_SHIFT
))
1524 new_height
= bound_y
*(new_width
/bound_x
);
1526 if (this->GetFixedWidth())
1527 new_width
= bound_x
;
1529 if (this->GetFixedHeight())
1530 new_height
= bound_y
;
1532 pt
->controlPointDragEndWidth
= new_width
;
1533 pt
->controlPointDragEndHeight
= new_height
;
1535 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1536 new_width
, new_height
);
1540 // Don't maintain the same centre point!
1541 double newX1
= wxMin(pt
->controlPointDragStartX
, x
);
1542 double newY1
= wxMin(pt
->controlPointDragStartY
, y
);
1543 double newX2
= wxMax(pt
->controlPointDragStartX
, x
);
1544 double newY2
= wxMax(pt
->controlPointDragStartY
, y
);
1545 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1547 newY1
= pt
->controlPointDragStartY
;
1548 newY2
= newY1
+ pt
->controlPointDragStartHeight
;
1550 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1552 newX1
= pt
->controlPointDragStartX
;
1553 newX2
= newX1
+ pt
->controlPointDragStartWidth
;
1555 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& (keys
& KEY_SHIFT
))
1557 double newH
= (double)((newX2
- newX1
)*(pt
->controlPointDragStartHeight
/pt
->controlPointDragStartWidth
));
1558 if (GetY() > pt
->controlPointDragStartY
)
1559 newY2
= (double)(newY1
+ newH
);
1561 newY1
= (double)(newY2
- newH
);
1563 double newWidth
= (double)(newX2
- newX1
);
1564 double newHeight
= (double)(newY2
- newY1
);
1566 pt
->controlPointDragPosX
= (double)(newX1
+ (newWidth
/2.0));
1567 pt
->controlPointDragPosY
= (double)(newY1
+ (newHeight
/2.0));
1568 if (this->GetFixedWidth())
1571 if (this->GetFixedHeight())
1572 newHeight
= bound_y
;
1574 pt
->controlPointDragEndWidth
= newWidth
;
1575 pt
->controlPointDragEndHeight
= newHeight
;
1576 this->GetEventHandler()->OnDrawOutline(dc
, pt
->controlPointDragPosX
, pt
->controlPointDragPosY
, newWidth
, newHeight
);
1580 void wxShape::OnSizingBeginDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int attachment
)
1582 m_canvas
->CaptureMouse();
1584 wxClientDC
dc(GetCanvas());
1585 GetCanvas()->PrepareDC(dc
);
1587 if (pt->m_eraseObject)
1591 dc
.SetLogicalFunction(wxXOR
);
1595 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1597 // Choose the 'opposite corner' of the object as the stationary
1598 // point in case this is non-centring resizing.
1599 if (pt
->GetX() < this->GetX())
1600 pt
->controlPointDragStartX
= (double)(this->GetX() + (bound_x
/2.0));
1602 pt
->controlPointDragStartX
= (double)(this->GetX() - (bound_x
/2.0));
1604 if (pt
->GetY() < this->GetY())
1605 pt
->controlPointDragStartY
= (double)(this->GetY() + (bound_y
/2.0));
1607 pt
->controlPointDragStartY
= (double)(this->GetY() - (bound_y
/2.0));
1609 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1610 pt
->controlPointDragStartY
= (double)(this->GetY() - (bound_y
/2.0));
1611 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1612 pt
->controlPointDragStartX
= (double)(this->GetX() - (bound_x
/2.0));
1614 // We may require the old width and height.
1615 pt
->controlPointDragStartWidth
= bound_x
;
1616 pt
->controlPointDragStartHeight
= bound_y
;
1618 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1619 dc
.SetPen(dottedPen
);
1620 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1622 if (this->GetCentreResize())
1624 double new_width
= (double)(2.0*fabs(x
- this->GetX()));
1625 double new_height
= (double)(2.0*fabs(y
- this->GetY()));
1627 // Constrain sizing according to what control point you're dragging
1628 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1629 new_height
= bound_y
;
1630 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1631 new_width
= bound_x
;
1632 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& (keys
& KEY_SHIFT
))
1633 new_height
= bound_y
*(new_width
/bound_x
);
1635 if (this->GetFixedWidth())
1636 new_width
= bound_x
;
1638 if (this->GetFixedHeight())
1639 new_height
= bound_y
;
1641 pt
->controlPointDragEndWidth
= new_width
;
1642 pt
->controlPointDragEndHeight
= new_height
;
1643 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1644 new_width
, new_height
);
1648 // Don't maintain the same centre point!
1649 double newX1
= wxMin(pt
->controlPointDragStartX
, x
);
1650 double newY1
= wxMin(pt
->controlPointDragStartY
, y
);
1651 double newX2
= wxMax(pt
->controlPointDragStartX
, x
);
1652 double newY2
= wxMax(pt
->controlPointDragStartY
, y
);
1653 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1655 newY1
= pt
->controlPointDragStartY
;
1656 newY2
= newY1
+ pt
->controlPointDragStartHeight
;
1658 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1660 newX1
= pt
->controlPointDragStartX
;
1661 newX2
= newX1
+ pt
->controlPointDragStartWidth
;
1663 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& (keys
& KEY_SHIFT
))
1665 double newH
= (double)((newX2
- newX1
)*(pt
->controlPointDragStartHeight
/pt
->controlPointDragStartWidth
));
1666 if (pt
->GetY() > pt
->controlPointDragStartY
)
1667 newY2
= (double)(newY1
+ newH
);
1669 newY1
= (double)(newY2
- newH
);
1671 double newWidth
= (double)(newX2
- newX1
);
1672 double newHeight
= (double)(newY2
- newY1
);
1674 pt
->controlPointDragPosX
= (double)(newX1
+ (newWidth
/2.0));
1675 pt
->controlPointDragPosY
= (double)(newY1
+ (newHeight
/2.0));
1676 if (this->GetFixedWidth())
1679 if (this->GetFixedHeight())
1680 newHeight
= bound_y
;
1682 pt
->controlPointDragEndWidth
= newWidth
;
1683 pt
->controlPointDragEndHeight
= newHeight
;
1684 this->GetEventHandler()->OnDrawOutline(dc
, pt
->controlPointDragPosX
, pt
->controlPointDragPosY
, newWidth
, newHeight
);
1688 void wxShape::OnSizingEndDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int attachment
)
1690 wxClientDC
dc(GetCanvas());
1691 GetCanvas()->PrepareDC(dc
);
1693 m_canvas
->ReleaseMouse();
1694 dc
.SetLogicalFunction(wxCOPY
);
1696 this->ResetControlPoints();
1700 if (!pt->m_eraseObject)
1704 this->SetSize(pt
->controlPointDragEndWidth
, pt
->controlPointDragEndHeight
);
1706 // The next operation could destroy this control point (it does for label objects,
1707 // via formatting the text), so save all values we're going to use, or
1708 // we'll be accessing garbage.
1709 wxShape
*theObject
= this;
1710 wxShapeCanvas
*theCanvas
= m_canvas
;
1711 bool eraseIt
= pt
->m_eraseObject
;
1713 if (theObject
->GetCentreResize())
1714 theObject
->Move(dc
, theObject
->GetX(), theObject
->GetY());
1716 theObject
->Move(dc
, pt
->controlPointDragPosX
, pt
->controlPointDragPosY
);
1720 theObject->Show(TRUE);
1723 // Recursively redraw links if we have a composite.
1724 if (theObject
->GetChildren().Number() > 0)
1725 theObject
->DrawLinks(dc
, -1, TRUE
);
1727 double width
, height
;
1728 theObject
->GetBoundingBoxMax(&width
, &height
);
1729 theObject
->GetEventHandler()->OnEndSize(width
, height
);
1731 if (!theCanvas
->GetQuickEditMode() && eraseIt
) theCanvas
->Redraw(dc
);
1736 // Polygon control points
1738 IMPLEMENT_DYNAMIC_CLASS(wxPolygonControlPoint
, wxControlPoint
)
1740 wxPolygonControlPoint::wxPolygonControlPoint(wxShapeCanvas
*theCanvas
, wxShape
*object
, double size
,
1741 wxRealPoint
*vertex
, double the_xoffset
, double the_yoffset
):
1742 wxControlPoint(theCanvas
, object
, size
, the_xoffset
, the_yoffset
, 0)
1744 m_polygonVertex
= vertex
;
1745 m_originalDistance
= 0.0;
1748 wxPolygonControlPoint::~wxPolygonControlPoint()
1752 // Calculate what new size would be, at end of resize
1753 void wxPolygonControlPoint::CalculateNewSize(double x
, double y
)
1757 GetShape()->GetBoundingBoxMin(&bound_x
, &bound_y
);
1759 double dist
= (double)sqrt((x
- m_shape
->GetX())*(x
- m_shape
->GetX()) +
1760 (y
- m_shape
->GetY())*(y
- m_shape
->GetY()));
1762 m_newSize
.x
= (double)(dist
/this->m_originalDistance
)*this->m_originalSize
.x
;
1763 m_newSize
.y
= (double)(dist
/this->m_originalDistance
)*this->m_originalSize
.y
;
1767 // Implement resizing polygon or moving the vertex.
1768 void wxPolygonControlPoint::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
1770 m_shape
->GetEventHandler()->OnSizingDragLeft(this, draw
, x
, y
, keys
, attachment
);
1773 void wxPolygonControlPoint::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
1775 m_shape
->GetEventHandler()->OnSizingBeginDragLeft(this, x
, y
, keys
, attachment
);
1778 void wxPolygonControlPoint::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
1780 m_shape
->GetEventHandler()->OnSizingEndDragLeft(this, x
, y
, keys
, attachment
);
1783 // Control points ('handles') redirect control to the actual shape, to make it easier
1784 // to override sizing behaviour.
1785 void wxPolygonShape::OnSizingDragLeft(wxControlPoint
* pt
, bool draw
, double x
, double y
, int keys
, int attachment
)
1787 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
1789 wxClientDC
dc(GetCanvas());
1790 GetCanvas()->PrepareDC(dc
);
1792 dc
.SetLogicalFunction(wxXOR
);
1794 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1795 dc
.SetPen(dottedPen
);
1796 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1798 if (0) // keys & KEY_CTRL)
1800 // TODO: mend this code. Currently we rely on altering the
1801 // actual points, but we should assume we're not, as per
1802 // the normal sizing case.
1803 m_canvas
->Snap(&x
, &y
);
1806 ppt
->m_polygonVertex
->x
= x
- this->GetX();
1807 ppt
->m_polygonVertex
->y
= y
- this->GetY();
1810 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1811 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1815 ppt
->CalculateNewSize(x
, y
);
1818 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1819 ppt
->GetNewSize().x
, ppt
->GetNewSize().y
);
1822 void wxPolygonShape::OnSizingBeginDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int attachment
)
1824 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
1826 wxClientDC
dc(GetCanvas());
1827 GetCanvas()->PrepareDC(dc
);
1831 dc
.SetLogicalFunction(wxXOR
);
1835 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1837 double dist
= (double)sqrt((x
- this->GetX())*(x
- this->GetX()) +
1838 (y
- this->GetY())*(y
- this->GetY()));
1839 ppt
->m_originalDistance
= dist
;
1840 ppt
->m_originalSize
.x
= bound_x
;
1841 ppt
->m_originalSize
.y
= bound_y
;
1843 if (ppt
->m_originalDistance
== 0.0) ppt
->m_originalDistance
= (double) 0.0001;
1845 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1846 dc
.SetPen(dottedPen
);
1847 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1849 if (0) // keys & KEY_CTRL)
1851 // TODO: mend this code. Currently we rely on altering the
1852 // actual points, but we should assume we're not, as per
1853 // the normal sizing case.
1854 m_canvas
->Snap(&x
, &y
);
1857 ppt
->m_polygonVertex
->x
= x
- this->GetX();
1858 ppt
->m_polygonVertex
->y
= y
- this->GetY();
1861 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1862 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1866 ppt
->CalculateNewSize(x
, y
);
1869 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1870 ppt
->GetNewSize().x
, ppt
->GetNewSize().y
);
1872 m_canvas
->CaptureMouse();
1875 void wxPolygonShape::OnSizingEndDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int attachment
)
1877 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
1879 wxClientDC
dc(GetCanvas());
1880 GetCanvas()->PrepareDC(dc
);
1882 m_canvas
->ReleaseMouse();
1883 dc
.SetLogicalFunction(wxCOPY
);
1885 // If we're changing shape, must reset the original points
1886 if (keys
& KEY_CTRL
)
1888 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1889 ((wxPolygonShape
*)this)->UpdateOriginalPoints();
1893 SetSize(ppt
->GetNewSize().x
, ppt
->GetNewSize().y
);
1896 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1897 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1900 this->ResetControlPoints();
1901 this->Move(dc
, this->GetX(), this->GetY());
1902 if (!m_canvas
->GetQuickEditMode()) m_canvas
->Redraw(dc
);
1909 IMPLEMENT_DYNAMIC_CLASS(wxShapeRegion
, wxObject
)
1911 wxShapeRegion::wxShapeRegion()
1914 m_font
= g_oglNormalFont
;
1922 m_regionProportionX
= -1.0;
1923 m_regionProportionY
= -1.0;
1924 m_formatMode
= FORMAT_CENTRE_HORIZ
| FORMAT_CENTRE_VERT
;
1926 m_textColour
= "BLACK";
1927 m_penColour
= "BLACK";
1928 m_penStyle
= wxSOLID
;
1929 m_actualColourObject
= NULL
;
1930 m_actualPenObject
= NULL
;
1933 wxShapeRegion::wxShapeRegion(wxShapeRegion
& region
)
1935 m_regionText
= region
.m_regionText
;
1936 m_regionName
= region
.m_regionName
;
1937 m_textColour
= region
.m_textColour
;
1939 m_font
= region
.m_font
;
1940 m_minHeight
= region
.m_minHeight
;
1941 m_minWidth
= region
.m_minWidth
;
1942 m_width
= region
.m_width
;
1943 m_height
= region
.m_height
;
1947 m_regionProportionX
= region
.m_regionProportionX
;
1948 m_regionProportionY
= region
.m_regionProportionY
;
1949 m_formatMode
= region
.m_formatMode
;
1950 m_actualColourObject
= NULL
;
1951 m_actualPenObject
= NULL
;
1952 m_penStyle
= region
.m_penStyle
;
1953 m_penColour
= region
.m_penColour
;
1956 wxNode
*node
= region
.m_formattedText
.First();
1959 wxShapeTextLine
*line
= (wxShapeTextLine
*)node
->Data();
1960 wxShapeTextLine
*new_line
=
1961 new wxShapeTextLine(line
->GetX(), line
->GetY(), line
->GetText());
1962 m_formattedText
.Append(new_line
);
1963 node
= node
->Next();
1967 wxShapeRegion::~wxShapeRegion()
1972 void wxShapeRegion::ClearText()
1974 wxNode
*node
= m_formattedText
.First();
1977 wxShapeTextLine
*line
= (wxShapeTextLine
*)node
->Data();
1978 wxNode
*next
= node
->Next();
1985 void wxShapeRegion::SetFont(wxFont
*f
)
1990 void wxShapeRegion::SetMinSize(double w
, double h
)
1996 void wxShapeRegion::SetSize(double w
, double h
)
2002 void wxShapeRegion::SetPosition(double xp
, double yp
)
2008 void wxShapeRegion::SetProportions(double xp
, double yp
)
2010 m_regionProportionX
= xp
;
2011 m_regionProportionY
= yp
;
2014 void wxShapeRegion::SetFormatMode(int mode
)
2016 m_formatMode
= mode
;
2019 void wxShapeRegion::SetColour(const wxString
& col
)
2022 m_actualColourObject
= NULL
;
2025 wxColour
*wxShapeRegion::GetActualColourObject()
2027 if (!m_actualColourObject
)
2028 m_actualColourObject
= wxTheColourDatabase
->FindColour(GetColour());
2029 if (!m_actualColourObject
)
2030 m_actualColourObject
= wxBLACK
;
2031 return m_actualColourObject
;
2034 void wxShapeRegion::SetPenColour(const wxString
& col
)
2037 m_actualPenObject
= NULL
;
2040 // Returns NULL if the pen is invisible
2041 // (different to pen being transparent; indicates that
2042 // region boundary should not be drawn.)
2043 wxPen
*wxShapeRegion::GetActualPen()
2045 if (m_actualPenObject
)
2046 return m_actualPenObject
;
2048 if (!m_penColour
) return NULL
;
2049 if (m_penColour
== "Invisible")
2051 m_actualPenObject
= wxThePenList
->FindOrCreatePen(m_penColour
, 1, m_penStyle
);
2052 return m_actualPenObject
;