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/deprecated/wxexpr.h>
37 #include <wx/ogl/basic.h>
38 #include <wx/ogl/basicp.h>
39 #include <wx/ogl/composit.h>
40 #include <wx/ogl/lines.h>
41 #include <wx/ogl/canvas.h>
42 #include <wx/ogl/divided.h>
43 #include <wx/ogl/misc.h>
45 // Control point types
46 // Rectangle and most other shapes
47 #define CONTROL_POINT_VERTICAL 1
48 #define CONTROL_POINT_HORIZONTAL 2
49 #define CONTROL_POINT_DIAGONAL 3
52 #define CONTROL_POINT_ENDPOINT_TO 4
53 #define CONTROL_POINT_ENDPOINT_FROM 5
54 #define CONTROL_POINT_LINE 6
56 // Two stage construction: need to call Create
57 IMPLEMENT_DYNAMIC_CLASS(wxPolygonShape
, wxShape
)
59 wxPolygonShape::wxPolygonShape()
62 m_originalPoints
= NULL
;
65 void wxPolygonShape::Create(wxList
*the_points
)
69 m_originalPoints
= the_points
;
71 // Duplicate the list of points
72 m_points
= new wxList
;
74 wxNode
*node
= the_points
->GetFirst();
77 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
78 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
79 m_points
->Append((wxObject
*) new_point
);
80 node
= node
->GetNext();
82 CalculateBoundingBox();
83 m_originalWidth
= m_boundWidth
;
84 m_originalHeight
= m_boundHeight
;
85 SetDefaultRegionSize();
88 wxPolygonShape::~wxPolygonShape()
93 void wxPolygonShape::ClearPoints()
97 wxNode
*node
= m_points
->GetFirst();
100 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
103 node
= m_points
->GetFirst();
108 if (m_originalPoints
)
110 wxNode
*node
= m_originalPoints
->GetFirst();
113 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
116 node
= m_originalPoints
->GetFirst();
118 delete m_originalPoints
;
119 m_originalPoints
= NULL
;
124 // Width and height. Centre of object is centre of box.
125 void wxPolygonShape::GetBoundingBoxMin(double *width
, double *height
)
127 *width
= m_boundWidth
;
128 *height
= m_boundHeight
;
131 void wxPolygonShape::CalculateBoundingBox()
133 // Calculate bounding box at construction (and presumably resize) time
135 double right
= -10000;
137 double bottom
= -10000;
139 wxNode
*node
= m_points
->GetFirst();
142 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
143 if (point
->x
< left
) left
= point
->x
;
144 if (point
->x
> right
) right
= point
->x
;
146 if (point
->y
< top
) top
= point
->y
;
147 if (point
->y
> bottom
) bottom
= point
->y
;
149 node
= node
->GetNext();
151 m_boundWidth
= right
- left
;
152 m_boundHeight
= bottom
- top
;
155 // Recalculates the centre of the polygon, and
156 // readjusts the point offsets accordingly.
157 // Necessary since the centre of the polygon
158 // is expected to be the real centre of the bounding
160 void wxPolygonShape::CalculatePolygonCentre()
163 double right
= -10000;
165 double bottom
= -10000;
167 wxNode
*node
= m_points
->GetFirst();
170 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
171 if (point
->x
< left
) left
= point
->x
;
172 if (point
->x
> right
) right
= point
->x
;
174 if (point
->y
< top
) top
= point
->y
;
175 if (point
->y
> bottom
) bottom
= point
->y
;
177 node
= node
->GetNext();
179 double bwidth
= right
- left
;
180 double bheight
= bottom
- top
;
182 double newCentreX
= (double)(left
+ (bwidth
/2.0));
183 double newCentreY
= (double)(top
+ (bheight
/2.0));
185 node
= m_points
->GetFirst();
188 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
189 point
->x
-= newCentreX
;
190 point
->y
-= newCentreY
;
191 node
= node
->GetNext();
193 m_xpos
+= newCentreX
;
194 m_ypos
+= newCentreY
;
197 bool PolylineHitTest(double n
, double xvec
[], double yvec
[],
198 double x1
, double y1
, double x2
, double y2
)
202 double lastx
= xvec
[0];
203 double lasty
= yvec
[0];
205 double min_ratio
= 1.0;
210 for (i
= 1; i
< n
; i
++)
212 oglCheckLineIntersection(x1
, y1
, x2
, y2
, lastx
, lasty
, xvec
[i
], yvec
[i
],
213 &line_ratio
, &other_ratio
);
214 if (line_ratio
!= 1.0)
216 // sprintf(buf, "Line ratio = %.2f, other ratio = %.2f\n", line_ratio, other_ratio);
217 // ClipsErrorFunction(buf);
221 if (line_ratio
< min_ratio
)
222 min_ratio
= line_ratio
;
225 // Do last (implicit) line if last and first doubles are not identical
226 if (!(xvec
[0] == lastx
&& yvec
[0] == lasty
))
228 oglCheckLineIntersection(x1
, y1
, x2
, y2
, lastx
, lasty
, xvec
[0], yvec
[0],
229 &line_ratio
, &other_ratio
);
230 if (line_ratio
!= 1.0)
232 // sprintf(buf, "Line ratio = %.2f, other ratio = %.2f\n", line_ratio, other_ratio);
233 // ClipsErrorFunction(buf);
235 if (line_ratio
< min_ratio
)
236 min_ratio
= line_ratio
;
238 // ClipsErrorFunction("\n");
242 bool wxPolygonShape::HitTest(double x
, double y
, int *attachment
, double *distance
)
244 // Imagine four lines radiating from this point. If all of these lines hit the polygon,
245 // we're inside it, otherwise we're not. Obviously we'd need more radiating lines
246 // to be sure of correct results for very strange (concave) shapes.
247 double endPointsX
[4];
248 double endPointsY
[4];
251 endPointsY
[0] = (double)(y
- 1000.0);
253 endPointsX
[1] = (double)(x
+ 1000.0);
257 endPointsY
[2] = (double)(y
+ 1000.0);
259 endPointsX
[3] = (double)(x
- 1000.0);
262 // Store polygon points in an array
263 int np
= m_points
->GetCount();
264 double *xpoints
= new double[np
];
265 double *ypoints
= new double[np
];
266 wxNode
*node
= m_points
->GetFirst();
270 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
271 xpoints
[i
] = point
->x
+ m_xpos
;
272 ypoints
[i
] = point
->y
+ m_ypos
;
273 node
= node
->GetNext();
277 // We assume it's inside the polygon UNLESS one or more
278 // lines don't hit the outline.
279 bool isContained
= TRUE
;
282 for (i
= 0; i
< noPoints
; i
++)
284 if (!PolylineHitTest(np
, xpoints
, ypoints
, x
, y
, endPointsX
[i
], endPointsY
[i
]))
289 ClipsErrorFunction("It's a hit!\n");
291 ClipsErrorFunction("No hit.\n");
299 int nearest_attachment
= 0;
301 // If a hit, check the attachment points within the object.
302 int n
= GetNumberOfAttachments();
303 double nearest
= 999999.0;
305 for (i
= 0; i
< n
; i
++)
308 if (GetAttachmentPositionEdge(i
, &xp
, &yp
))
310 double l
= (double)sqrt(((xp
- x
) * (xp
- x
)) +
311 ((yp
- y
) * (yp
- y
)));
315 nearest_attachment
= i
;
319 *attachment
= nearest_attachment
;
324 // Really need to be able to reset the shape! Otherwise, if the
325 // points ever go to zero, we've lost it, and can't resize.
326 void wxPolygonShape::SetSize(double new_width
, double new_height
, bool recursive
)
328 SetAttachmentSize(new_width
, new_height
);
330 // Multiply all points by proportion of new size to old size
331 double x_proportion
= (double)(fabs(new_width
/m_originalWidth
));
332 double y_proportion
= (double)(fabs(new_height
/m_originalHeight
));
334 wxNode
*node
= m_points
->GetFirst();
335 wxNode
*original_node
= m_originalPoints
->GetFirst();
336 while (node
&& original_node
)
338 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
339 wxRealPoint
*original_point
= (wxRealPoint
*)original_node
->GetData();
341 point
->x
= (original_point
->x
* x_proportion
);
342 point
->y
= (original_point
->y
* y_proportion
);
344 node
= node
->GetNext();
345 original_node
= original_node
->GetNext();
348 // CalculateBoundingBox();
349 m_boundWidth
= (double)fabs(new_width
);
350 m_boundHeight
= (double)fabs(new_height
);
351 SetDefaultRegionSize();
354 // Make the original points the same as the working points
355 void wxPolygonShape::UpdateOriginalPoints()
357 if (!m_originalPoints
) m_originalPoints
= new wxList
;
358 wxNode
*original_node
= m_originalPoints
->GetFirst();
359 while (original_node
)
361 wxNode
*next_node
= original_node
->GetNext();
362 wxRealPoint
*original_point
= (wxRealPoint
*)original_node
->GetData();
363 delete original_point
;
364 delete original_node
;
366 original_node
= next_node
;
369 wxNode
*node
= m_points
->GetFirst();
372 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
373 wxRealPoint
*original_point
= new wxRealPoint(point
->x
, point
->y
);
374 m_originalPoints
->Append((wxObject
*) original_point
);
376 node
= node
->GetNext();
378 CalculateBoundingBox();
379 m_originalWidth
= m_boundWidth
;
380 m_originalHeight
= m_boundHeight
;
383 void wxPolygonShape::AddPolygonPoint(int pos
)
385 wxNode
*node
= m_points
->Item(pos
);
386 if (!node
) node
= m_points
->GetFirst();
387 wxRealPoint
*firstPoint
= (wxRealPoint
*)node
->GetData();
389 wxNode
*node2
= m_points
->Item(pos
+ 1);
390 if (!node2
) node2
= m_points
->GetFirst();
391 wxRealPoint
*secondPoint
= (wxRealPoint
*)node2
->GetData();
393 double x
= (double)((secondPoint
->x
- firstPoint
->x
)/2.0 + firstPoint
->x
);
394 double y
= (double)((secondPoint
->y
- firstPoint
->y
)/2.0 + firstPoint
->y
);
395 wxRealPoint
*point
= new wxRealPoint(x
, y
);
397 if (pos
>= (m_points
->GetCount() - 1))
398 m_points
->Append((wxObject
*) point
);
400 m_points
->Insert(node2
, (wxObject
*) point
);
402 UpdateOriginalPoints();
406 DeleteControlPoints();
411 void wxPolygonShape::DeletePolygonPoint(int pos
)
413 wxNode
*node
= m_points
->Item(pos
);
416 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
419 UpdateOriginalPoints();
422 DeleteControlPoints();
428 // Assume (x1, y1) is centre of box (most generally, line end at box)
429 bool wxPolygonShape::GetPerimeterPoint(double x1
, double y1
,
430 double x2
, double y2
,
431 double *x3
, double *y3
)
433 int n
= m_points
->GetCount();
435 // First check for situation where the line is vertical,
436 // and we would want to connect to a point on that vertical --
437 // oglFindEndForPolyline can't cope with this (the arrow
438 // gets drawn to the wrong place).
439 if ((m_attachmentMode
== ATTACHMENT_MODE_NONE
) && (x1
== x2
))
441 // Look for the point we'd be connecting to. This is
443 wxNode
*node
= m_points
->GetFirst();
446 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
449 if ((y2
> y1
) && (point
->y
> 0.0))
451 *x3
= point
->x
+ m_xpos
;
452 *y3
= point
->y
+ m_ypos
;
455 else if ((y2
< y1
) && (point
->y
< 0.0))
457 *x3
= point
->x
+ m_xpos
;
458 *y3
= point
->y
+ m_ypos
;
462 node
= node
->GetNext();
466 double *xpoints
= new double[n
];
467 double *ypoints
= new double[n
];
469 wxNode
*node
= m_points
->GetFirst();
473 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
474 xpoints
[i
] = point
->x
+ m_xpos
;
475 ypoints
[i
] = point
->y
+ m_ypos
;
476 node
= node
->GetNext();
480 oglFindEndForPolyline(n
, xpoints
, ypoints
,
481 x1
, y1
, x2
, y2
, x3
, y3
);
489 void wxPolygonShape::OnDraw(wxDC
& dc
)
491 int n
= m_points
->GetCount();
492 wxPoint
*intPoints
= new wxPoint
[n
];
494 for (i
= 0; i
< n
; i
++)
496 wxRealPoint
* point
= (wxRealPoint
*) m_points
->Item(i
)->GetData();
497 intPoints
[i
].x
= WXROUND(point
->x
);
498 intPoints
[i
].y
= WXROUND(point
->y
);
501 if (m_shadowMode
!= SHADOW_NONE
)
504 dc
.SetBrush(* m_shadowBrush
);
505 dc
.SetPen(* g_oglTransparentPen
);
507 dc
.DrawPolygon(n
, intPoints
, WXROUND(m_xpos
+ m_shadowOffsetX
), WXROUND(m_ypos
+ m_shadowOffsetY
));
512 if (m_pen
->GetWidth() == 0)
513 dc
.SetPen(* g_oglTransparentPen
);
518 dc
.SetBrush(* m_brush
);
519 dc
.DrawPolygon(n
, intPoints
, WXROUND(m_xpos
), WXROUND(m_ypos
));
524 void wxPolygonShape::OnDrawOutline(wxDC
& dc
, double x
, double y
, double w
, double h
)
526 dc
.SetBrush(* wxTRANSPARENT_BRUSH
);
527 // Multiply all points by proportion of new size to old size
528 double x_proportion
= (double)(fabs(w
/m_originalWidth
));
529 double y_proportion
= (double)(fabs(h
/m_originalHeight
));
531 int n
= m_originalPoints
->GetCount();
532 wxPoint
*intPoints
= new wxPoint
[n
];
534 for (i
= 0; i
< n
; i
++)
536 wxRealPoint
* point
= (wxRealPoint
*) m_originalPoints
->Item(i
)->GetData();
537 intPoints
[i
].x
= WXROUND(x_proportion
* point
->x
);
538 intPoints
[i
].y
= WXROUND(y_proportion
* point
->y
);
540 dc
.DrawPolygon(n
, intPoints
, WXROUND(x
), WXROUND(y
));
544 // Make as many control points as there are vertices.
545 void wxPolygonShape::MakeControlPoints()
547 wxNode
*node
= m_points
->GetFirst();
550 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
551 wxPolygonControlPoint
*control
= new wxPolygonControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
,
552 point
, point
->x
, point
->y
);
553 m_canvas
->AddShape(control
);
554 m_controlPoints
.Append(control
);
555 node
= node
->GetNext();
559 void wxPolygonShape::ResetControlPoints()
561 wxNode
*node
= m_points
->GetFirst();
562 wxNode
*controlPointNode
= m_controlPoints
.GetFirst();
563 while (node
&& controlPointNode
)
565 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
566 wxPolygonControlPoint
*controlPoint
= (wxPolygonControlPoint
*)controlPointNode
->GetData();
568 controlPoint
->m_xoffset
= point
->x
;
569 controlPoint
->m_yoffset
= point
->y
;
570 controlPoint
->m_polygonVertex
= point
;
572 node
= node
->GetNext();
573 controlPointNode
= controlPointNode
->GetNext();
579 void wxPolygonShape::WriteAttributes(wxExpr
*clause
)
581 wxShape::WriteAttributes(clause
);
583 clause
->AddAttributeValue(wxT("x"), m_xpos
);
584 clause
->AddAttributeValue(wxT("y"), m_ypos
);
586 // Make a list of lists for the coordinates
587 wxExpr
*list
= new wxExpr(wxExprList
);
588 wxNode
*node
= m_points
->GetFirst();
591 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
592 wxExpr
*point_list
= new wxExpr(wxExprList
);
593 wxExpr
*x_expr
= new wxExpr((double)point
->x
);
594 wxExpr
*y_expr
= new wxExpr((double)point
->y
);
596 point_list
->Append(x_expr
);
597 point_list
->Append(y_expr
);
598 list
->Append(point_list
);
600 node
= node
->GetNext();
602 clause
->AddAttributeValue(wxT("points"), list
);
604 // Save the original (unscaled) points
605 list
= new wxExpr(wxExprList
);
606 node
= m_originalPoints
->GetFirst();
609 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
610 wxExpr
*point_list
= new wxExpr(wxExprList
);
611 wxExpr
*x_expr
= new wxExpr((double) point
->x
);
612 wxExpr
*y_expr
= new wxExpr((double) point
->y
);
613 point_list
->Append(x_expr
);
614 point_list
->Append(y_expr
);
615 list
->Append(point_list
);
617 node
= node
->GetNext();
619 clause
->AddAttributeValue(wxT("m_originalPoints"), list
);
622 void wxPolygonShape::ReadAttributes(wxExpr
*clause
)
624 wxShape::ReadAttributes(clause
);
626 // Read a list of lists
627 m_points
= new wxList
;
628 m_originalPoints
= new wxList
;
630 wxExpr
*points_list
= NULL
;
631 clause
->AssignAttributeValue(wxT("points"), &points_list
);
633 // If no points_list, don't crash!! Assume a diamond instead.
634 double the_height
= 100.0;
635 double the_width
= 100.0;
638 wxRealPoint
*point
= new wxRealPoint(0.0, (-the_height
/2));
639 m_points
->Append((wxObject
*) point
);
641 point
= new wxRealPoint((the_width
/2), 0.0);
642 m_points
->Append((wxObject
*) point
);
644 point
= new wxRealPoint(0.0, (the_height
/2));
645 m_points
->Append((wxObject
*) point
);
647 point
= new wxRealPoint((-the_width
/2), 0.0);
648 m_points
->Append((wxObject
*) point
);
650 point
= new wxRealPoint(0.0, (-the_height
/2));
651 m_points
->Append((wxObject
*) point
);
655 wxExpr
*node
= points_list
->value
.first
;
659 wxExpr
*xexpr
= node
->value
.first
;
660 long x
= xexpr
->IntegerValue();
662 wxExpr
*yexpr
= xexpr
->next
;
663 long y
= yexpr
->IntegerValue();
665 wxRealPoint
*point
= new wxRealPoint((double)x
, (double)y
);
666 m_points
->Append((wxObject
*) point
);
673 clause
->AssignAttributeValue(wxT("m_originalPoints"), &points_list
);
675 // If no points_list, don't crash!! Assume a diamond instead.
678 wxRealPoint
*point
= new wxRealPoint(0.0, (-the_height
/2));
679 m_originalPoints
->Append((wxObject
*) point
);
681 point
= new wxRealPoint((the_width
/2), 0.0);
682 m_originalPoints
->Append((wxObject
*) point
);
684 point
= new wxRealPoint(0.0, (the_height
/2));
685 m_originalPoints
->Append((wxObject
*) point
);
687 point
= new wxRealPoint((-the_width
/2), 0.0);
688 m_originalPoints
->Append((wxObject
*) point
);
690 point
= new wxRealPoint(0.0, (-the_height
/2));
691 m_originalPoints
->Append((wxObject
*) point
);
693 m_originalWidth
= the_width
;
694 m_originalHeight
= the_height
;
698 wxExpr
*node
= points_list
->value
.first
;
701 double max_x
= -1000;
702 double max_y
= -1000;
705 wxExpr
*xexpr
= node
->value
.first
;
706 long x
= xexpr
->IntegerValue();
708 wxExpr
*yexpr
= xexpr
->next
;
709 long y
= yexpr
->IntegerValue();
711 wxRealPoint
*point
= new wxRealPoint((double)x
, (double)y
);
712 m_originalPoints
->Append((wxObject
*) point
);
725 m_originalWidth
= max_x
- min_x
;
726 m_originalHeight
= max_y
- min_y
;
729 CalculateBoundingBox();
733 void wxPolygonShape::Copy(wxShape
& copy
)
737 wxASSERT( copy
.IsKindOf(CLASSINFO(wxPolygonShape
)) );
739 wxPolygonShape
& polyCopy
= (wxPolygonShape
&) copy
;
741 polyCopy
.ClearPoints();
743 polyCopy
.m_points
= new wxList
;
744 polyCopy
.m_originalPoints
= new wxList
;
746 wxNode
*node
= m_points
->GetFirst();
749 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
750 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
751 polyCopy
.m_points
->Append((wxObject
*) new_point
);
752 node
= node
->GetNext();
754 node
= m_originalPoints
->GetFirst();
757 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
758 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
759 polyCopy
.m_originalPoints
->Append((wxObject
*) new_point
);
760 node
= node
->GetNext();
762 polyCopy
.m_boundWidth
= m_boundWidth
;
763 polyCopy
.m_boundHeight
= m_boundHeight
;
764 polyCopy
.m_originalWidth
= m_originalWidth
;
765 polyCopy
.m_originalHeight
= m_originalHeight
;
768 int wxPolygonShape::GetNumberOfAttachments() const
770 int maxN
= (m_points
? (m_points
->GetCount() - 1) : 0);
771 wxNode
*node
= m_attachmentPoints
.GetFirst();
774 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->GetData();
775 if (point
->m_id
> maxN
)
777 node
= node
->GetNext();
782 bool wxPolygonShape::GetAttachmentPosition(int attachment
, double *x
, double *y
,
783 int nth
, int no_arcs
, wxLineShape
*line
)
785 if ((m_attachmentMode
== ATTACHMENT_MODE_EDGE
) && m_points
&& attachment
< m_points
->GetCount())
787 wxRealPoint
*point
= (wxRealPoint
*)m_points
->Item(attachment
)->GetData();
788 *x
= point
->x
+ m_xpos
;
789 *y
= point
->y
+ m_ypos
;
793 { return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
); }
796 bool wxPolygonShape::AttachmentIsValid(int attachment
) const
801 if ((attachment
>= 0) && (attachment
< m_points
->GetCount()))
804 wxNode
*node
= m_attachmentPoints
.GetFirst();
807 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->GetData();
808 if (point
->m_id
== attachment
)
810 node
= node
->GetNext();
815 // Rotate about the given axis by the given amount in radians
816 void wxPolygonShape::Rotate(double x
, double y
, double theta
)
818 double actualTheta
= theta
-m_rotation
;
820 // Rotate attachment points
821 double sinTheta
= (double)sin(actualTheta
);
822 double cosTheta
= (double)cos(actualTheta
);
823 wxNode
*node
= m_attachmentPoints
.GetFirst();
826 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->GetData();
827 double x1
= point
->m_x
;
828 double y1
= point
->m_y
;
829 point
->m_x
= x1
*cosTheta
- y1
*sinTheta
+ x
*(1.0 - cosTheta
) + y
*sinTheta
;
830 point
->m_y
= x1
*sinTheta
+ y1
*cosTheta
+ y
*(1.0 - cosTheta
) + x
*sinTheta
;
831 node
= node
->GetNext();
834 node
= m_points
->GetFirst();
837 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
838 double x1
= point
->x
;
839 double y1
= point
->y
;
840 point
->x
= x1
*cosTheta
- y1
*sinTheta
+ x
*(1.0 - cosTheta
) + y
*sinTheta
;
841 point
->y
= x1
*sinTheta
+ y1
*cosTheta
+ y
*(1.0 - cosTheta
) + x
*sinTheta
;
842 node
= node
->GetNext();
844 node
= m_originalPoints
->GetFirst();
847 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
848 double x1
= point
->x
;
849 double y1
= point
->y
;
850 point
->x
= x1
*cosTheta
- y1
*sinTheta
+ x
*(1.0 - cosTheta
) + y
*sinTheta
;
851 point
->y
= x1
*sinTheta
+ y1
*cosTheta
+ y
*(1.0 - cosTheta
) + x
*sinTheta
;
852 node
= node
->GetNext();
857 CalculatePolygonCentre();
858 CalculateBoundingBox();
859 ResetControlPoints();
864 IMPLEMENT_DYNAMIC_CLASS(wxRectangleShape
, wxShape
)
866 wxRectangleShape::wxRectangleShape(double w
, double h
)
868 m_width
= w
; m_height
= h
; m_cornerRadius
= 0.0;
869 SetDefaultRegionSize();
872 void wxRectangleShape::OnDraw(wxDC
& dc
)
874 double x1
= (double)(m_xpos
- m_width
/2.0);
875 double y1
= (double)(m_ypos
- m_height
/2.0);
877 if (m_shadowMode
!= SHADOW_NONE
)
880 dc
.SetBrush(* m_shadowBrush
);
881 dc
.SetPen(* g_oglTransparentPen
);
883 if (m_cornerRadius
!= 0.0)
884 dc
.DrawRoundedRectangle(WXROUND(x1
+ m_shadowOffsetX
), WXROUND(y1
+ m_shadowOffsetY
),
885 WXROUND(m_width
), WXROUND(m_height
), m_cornerRadius
);
887 dc
.DrawRectangle(WXROUND(x1
+ m_shadowOffsetX
), WXROUND(y1
+ m_shadowOffsetY
), WXROUND(m_width
), WXROUND(m_height
));
892 if (m_pen
->GetWidth() == 0)
893 dc
.SetPen(* g_oglTransparentPen
);
898 dc
.SetBrush(* m_brush
);
900 if (m_cornerRadius
!= 0.0)
901 dc
.DrawRoundedRectangle(WXROUND(x1
), WXROUND(y1
), WXROUND(m_width
), WXROUND(m_height
), m_cornerRadius
);
903 dc
.DrawRectangle(WXROUND(x1
), WXROUND(y1
), WXROUND(m_width
), WXROUND(m_height
));
906 void wxRectangleShape::GetBoundingBoxMin(double *the_width
, double *the_height
)
908 *the_width
= m_width
;
909 *the_height
= m_height
;
912 void wxRectangleShape::SetSize(double x
, double y
, bool recursive
)
914 SetAttachmentSize(x
, y
);
915 m_width
= (double)wxMax(x
, 1.0);
916 m_height
= (double)wxMax(y
, 1.0);
917 SetDefaultRegionSize();
920 void wxRectangleShape::SetCornerRadius(double rad
)
922 m_cornerRadius
= rad
;
925 // Assume (x1, y1) is centre of box (most generally, line end at box)
926 bool wxRectangleShape::GetPerimeterPoint(double x1
, double y1
,
927 double x2
, double y2
,
928 double *x3
, double *y3
)
930 double bound_x
, bound_y
;
931 GetBoundingBoxMax(&bound_x
, &bound_y
);
932 oglFindEndForBox(bound_x
, bound_y
, m_xpos
, m_ypos
, x2
, y2
, x3
, y3
);
938 void wxRectangleShape::WriteAttributes(wxExpr
*clause
)
940 wxShape::WriteAttributes(clause
);
941 clause
->AddAttributeValue(wxT("x"), m_xpos
);
942 clause
->AddAttributeValue(wxT("y"), m_ypos
);
944 clause
->AddAttributeValue(wxT("width"), m_width
);
945 clause
->AddAttributeValue(wxT("height"), m_height
);
946 if (m_cornerRadius
!= 0.0)
947 clause
->AddAttributeValue(wxT("corner"), m_cornerRadius
);
950 void wxRectangleShape::ReadAttributes(wxExpr
*clause
)
952 wxShape::ReadAttributes(clause
);
953 clause
->AssignAttributeValue(wxT("width"), &m_width
);
954 clause
->AssignAttributeValue(wxT("height"), &m_height
);
955 clause
->AssignAttributeValue(wxT("corner"), &m_cornerRadius
);
957 // In case we're reading an old file, set the region's size
958 if (m_regions
.GetCount() == 1)
960 wxShapeRegion
*region
= (wxShapeRegion
*)m_regions
.GetFirst()->GetData();
961 region
->SetSize(m_width
, m_height
);
966 void wxRectangleShape::Copy(wxShape
& copy
)
970 wxASSERT( copy
.IsKindOf(CLASSINFO(wxRectangleShape
)) );
972 wxRectangleShape
& rectCopy
= (wxRectangleShape
&) copy
;
973 rectCopy
.m_width
= m_width
;
974 rectCopy
.m_height
= m_height
;
975 rectCopy
.m_cornerRadius
= m_cornerRadius
;
978 int wxRectangleShape::GetNumberOfAttachments() const
980 return wxShape::GetNumberOfAttachments();
984 // There are 4 attachment points on a rectangle - 0 = top, 1 = right, 2 = bottom,
986 bool wxRectangleShape::GetAttachmentPosition(int attachment
, double *x
, double *y
,
987 int nth
, int no_arcs
, wxLineShape
*line
)
989 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
992 // Text object (no box)
994 IMPLEMENT_DYNAMIC_CLASS(wxTextShape
, wxRectangleShape
)
996 wxTextShape::wxTextShape(double width
, double height
):
997 wxRectangleShape(width
, height
)
1001 void wxTextShape::OnDraw(wxDC
& dc
)
1005 void wxTextShape::Copy(wxShape
& copy
)
1007 wxRectangleShape::Copy(copy
);
1011 void wxTextShape::WriteAttributes(wxExpr
*clause
)
1013 wxRectangleShape::WriteAttributes(clause
);
1019 IMPLEMENT_DYNAMIC_CLASS(wxEllipseShape
, wxShape
)
1021 wxEllipseShape::wxEllipseShape(double w
, double h
)
1023 m_width
= w
; m_height
= h
;
1024 SetDefaultRegionSize();
1027 void wxEllipseShape::GetBoundingBoxMin(double *w
, double *h
)
1029 *w
= m_width
; *h
= m_height
;
1032 bool wxEllipseShape::GetPerimeterPoint(double x1
, double y1
,
1033 double x2
, double y2
,
1034 double *x3
, double *y3
)
1036 double bound_x
, bound_y
;
1037 GetBoundingBoxMax(&bound_x
, &bound_y
);
1039 // oglFindEndForBox(bound_x, bound_y, m_xpos, m_ypos, x2, y2, x3, y3);
1040 oglDrawArcToEllipse(m_xpos
, m_ypos
, bound_x
, bound_y
, x2
, y2
, x1
, y1
, x3
, y3
);
1045 void wxEllipseShape::OnDraw(wxDC
& dc
)
1047 if (m_shadowMode
!= SHADOW_NONE
)
1050 dc
.SetBrush(* m_shadowBrush
);
1051 dc
.SetPen(* g_oglTransparentPen
);
1052 dc
.DrawEllipse((long) ((m_xpos
- GetWidth()/2) + m_shadowOffsetX
),
1053 (long) ((m_ypos
- GetHeight()/2) + m_shadowOffsetY
),
1054 (long) GetWidth(), (long) GetHeight());
1059 if (m_pen
->GetWidth() == 0)
1060 dc
.SetPen(* g_oglTransparentPen
);
1065 dc
.SetBrush(* m_brush
);
1066 dc
.DrawEllipse((long) (m_xpos
- GetWidth()/2), (long) (m_ypos
- GetHeight()/2), (long) GetWidth(), (long) GetHeight());
1069 void wxEllipseShape::SetSize(double x
, double y
, bool recursive
)
1071 SetAttachmentSize(x
, y
);
1074 SetDefaultRegionSize();
1078 void wxEllipseShape::WriteAttributes(wxExpr
*clause
)
1080 wxShape::WriteAttributes(clause
);
1081 clause
->AddAttributeValue(wxT("x"), m_xpos
);
1082 clause
->AddAttributeValue(wxT("y"), m_ypos
);
1084 clause
->AddAttributeValue(wxT("width"), m_width
);
1085 clause
->AddAttributeValue(wxT("height"), m_height
);
1088 void wxEllipseShape::ReadAttributes(wxExpr
*clause
)
1090 wxShape::ReadAttributes(clause
);
1091 clause
->AssignAttributeValue(wxT("width"), &m_width
);
1092 clause
->AssignAttributeValue(wxT("height"), &m_height
);
1094 // In case we're reading an old file, set the region's size
1095 if (m_regions
.GetCount() == 1)
1097 wxShapeRegion
*region
= (wxShapeRegion
*)m_regions
.GetFirst()->GetData();
1098 region
->SetSize(m_width
, m_height
);
1103 void wxEllipseShape::Copy(wxShape
& copy
)
1105 wxShape::Copy(copy
);
1107 wxASSERT( copy
.IsKindOf(CLASSINFO(wxEllipseShape
)) );
1109 wxEllipseShape
& ellipseCopy
= (wxEllipseShape
&) copy
;
1111 ellipseCopy
.m_width
= m_width
;
1112 ellipseCopy
.m_height
= m_height
;
1115 int wxEllipseShape::GetNumberOfAttachments() const
1117 return wxShape::GetNumberOfAttachments();
1120 // There are 4 attachment points on an ellipse - 0 = top, 1 = right, 2 = bottom,
1122 bool wxEllipseShape::GetAttachmentPosition(int attachment
, double *x
, double *y
,
1123 int nth
, int no_arcs
, wxLineShape
*line
)
1125 if (m_attachmentMode
== ATTACHMENT_MODE_BRANCHING
)
1126 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
1128 if (m_attachmentMode
!= ATTACHMENT_MODE_NONE
)
1130 double top
= (double)(m_ypos
+ m_height
/2.0);
1131 double bottom
= (double)(m_ypos
- m_height
/2.0);
1132 double left
= (double)(m_xpos
- m_width
/2.0);
1133 double right
= (double)(m_xpos
+ m_width
/2.0);
1135 int physicalAttachment
= LogicalToPhysicalAttachment(attachment
);
1137 switch (physicalAttachment
)
1141 if (m_spaceAttachments
)
1142 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
1145 // We now have the point on the bounding box: but get the point on the ellipse
1146 // by imagining a vertical line from (*x, m_ypos - m_height- 500) to (*x, m_ypos) intersecting
1148 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, *x
, (double)(m_ypos
-m_height
-500), *x
, m_ypos
, x
, y
);
1154 if (m_spaceAttachments
)
1155 *y
= bottom
+ (nth
+ 1)*m_height
/(no_arcs
+ 1);
1157 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, (double)(m_xpos
+m_width
+500), *y
, m_xpos
, *y
, x
, y
);
1162 if (m_spaceAttachments
)
1163 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
1166 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, *x
, (double)(m_ypos
+m_height
+500), *x
, m_ypos
, x
, y
);
1172 if (m_spaceAttachments
)
1173 *y
= bottom
+ (nth
+ 1)*m_height
/(no_arcs
+ 1);
1175 oglDrawArcToEllipse(m_xpos
, m_ypos
, m_width
, m_height
, (double)(m_xpos
-m_width
-500), *y
, m_xpos
, *y
, x
, y
);
1180 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
1187 { *x
= m_xpos
; *y
= m_ypos
; return TRUE
; }
1192 IMPLEMENT_DYNAMIC_CLASS(wxCircleShape
, wxEllipseShape
)
1194 wxCircleShape::wxCircleShape(double diameter
):wxEllipseShape(diameter
, diameter
)
1196 SetMaintainAspectRatio(TRUE
);
1199 void wxCircleShape::Copy(wxShape
& copy
)
1201 wxEllipseShape::Copy(copy
);
1204 bool wxCircleShape::GetPerimeterPoint(double x1
, double y1
,
1205 double x2
, double y2
,
1206 double *x3
, double *y3
)
1208 oglFindEndForCircle(m_width
/2,
1209 m_xpos
, m_ypos
, // Centre of circle
1210 x2
, y2
, // Other end of line
1218 double wxControlPoint::sm_controlPointDragStartX
= 0.0;
1219 double wxControlPoint::sm_controlPointDragStartY
= 0.0;
1220 double wxControlPoint::sm_controlPointDragStartWidth
= 0.0;
1221 double wxControlPoint::sm_controlPointDragStartHeight
= 0.0;
1222 double wxControlPoint::sm_controlPointDragEndWidth
= 0.0;
1223 double wxControlPoint::sm_controlPointDragEndHeight
= 0.0;
1224 double wxControlPoint::sm_controlPointDragPosX
= 0.0;
1225 double wxControlPoint::sm_controlPointDragPosY
= 0.0;
1227 IMPLEMENT_DYNAMIC_CLASS(wxControlPoint
, wxRectangleShape
)
1229 wxControlPoint::wxControlPoint(wxShapeCanvas
*theCanvas
, wxShape
*object
, double size
, double the_xoffset
, double the_yoffset
, int the_type
):wxRectangleShape(size
, size
)
1231 m_canvas
= theCanvas
;
1233 m_xoffset
= the_xoffset
;
1234 m_yoffset
= the_yoffset
;
1236 SetPen(g_oglBlackForegroundPen
);
1237 SetBrush(wxBLACK_BRUSH
);
1240 m_eraseObject
= TRUE
;
1243 wxControlPoint::~wxControlPoint()
1247 // Don't even attempt to draw any text - waste of time!
1248 void wxControlPoint::OnDrawContents(wxDC
& dc
)
1252 void wxControlPoint::OnDraw(wxDC
& dc
)
1254 m_xpos
= m_shape
->GetX() + m_xoffset
;
1255 m_ypos
= m_shape
->GetY() + m_yoffset
;
1256 wxRectangleShape::OnDraw(dc
);
1259 void wxControlPoint::OnErase(wxDC
& dc
)
1261 wxRectangleShape::OnErase(dc
);
1264 // Implement resizing of canvas object
1265 void wxControlPoint::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
1267 m_shape
->GetEventHandler()->OnSizingDragLeft(this, draw
, x
, y
, keys
, attachment
);
1270 void wxControlPoint::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
1272 m_shape
->GetEventHandler()->OnSizingBeginDragLeft(this, x
, y
, keys
, attachment
);
1275 void wxControlPoint::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
1277 m_shape
->GetEventHandler()->OnSizingEndDragLeft(this, x
, y
, keys
, attachment
);
1280 int wxControlPoint::GetNumberOfAttachments() const
1285 bool wxControlPoint::GetAttachmentPosition(int attachment
, double *x
, double *y
,
1286 int nth
, int no_arcs
, wxLineShape
*line
)
1288 *x
= m_xpos
; *y
= m_ypos
;
1292 // Control points ('handles') redirect control to the actual shape, to make it easier
1293 // to override sizing behaviour.
1294 void wxShape::OnSizingDragLeft(wxControlPoint
* pt
, bool draw
, double x
, double y
, int keys
, int attachment
)
1298 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1300 wxClientDC
dc(GetCanvas());
1301 GetCanvas()->PrepareDC(dc
);
1303 dc
.SetLogicalFunction(OGLRBLF
);
1305 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1306 dc
.SetPen(dottedPen
);
1307 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1309 if (this->GetCentreResize())
1311 // Maintain the same centre point.
1312 double new_width
= (double)(2.0*fabs(x
- this->GetX()));
1313 double new_height
= (double)(2.0*fabs(y
- this->GetY()));
1315 // Constrain sizing according to what control point you're dragging
1316 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1318 if (GetMaintainAspectRatio())
1320 new_height
= bound_y
*(new_width
/bound_x
);
1323 new_height
= bound_y
;
1325 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1327 if (GetMaintainAspectRatio())
1329 new_width
= bound_x
*(new_height
/bound_y
);
1332 new_width
= bound_x
;
1334 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& (keys
& KEY_SHIFT
))
1335 new_height
= bound_y
*(new_width
/bound_x
);
1337 if (this->GetFixedWidth())
1338 new_width
= bound_x
;
1340 if (this->GetFixedHeight())
1341 new_height
= bound_y
;
1343 pt
->sm_controlPointDragEndWidth
= new_width
;
1344 pt
->sm_controlPointDragEndHeight
= new_height
;
1346 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1347 new_width
, new_height
);
1351 // Don't maintain the same centre point!
1352 double newX1
= wxMin(pt
->sm_controlPointDragStartX
, x
);
1353 double newY1
= wxMin(pt
->sm_controlPointDragStartY
, y
);
1354 double newX2
= wxMax(pt
->sm_controlPointDragStartX
, x
);
1355 double newY2
= wxMax(pt
->sm_controlPointDragStartY
, y
);
1356 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1358 newY1
= pt
->sm_controlPointDragStartY
;
1359 newY2
= newY1
+ pt
->sm_controlPointDragStartHeight
;
1361 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1363 newX1
= pt
->sm_controlPointDragStartX
;
1364 newX2
= newX1
+ pt
->sm_controlPointDragStartWidth
;
1366 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& ((keys
& KEY_SHIFT
) || GetMaintainAspectRatio()))
1368 double newH
= (double)((newX2
- newX1
)*(pt
->sm_controlPointDragStartHeight
/pt
->sm_controlPointDragStartWidth
));
1369 if (GetY() > pt
->sm_controlPointDragStartY
)
1370 newY2
= (double)(newY1
+ newH
);
1372 newY1
= (double)(newY2
- newH
);
1374 double newWidth
= (double)(newX2
- newX1
);
1375 double newHeight
= (double)(newY2
- newY1
);
1377 if (pt
->m_type
== CONTROL_POINT_VERTICAL
&& GetMaintainAspectRatio())
1379 newWidth
= bound_x
* (newHeight
/bound_y
) ;
1382 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
&& GetMaintainAspectRatio())
1384 newHeight
= bound_y
* (newWidth
/bound_x
) ;
1387 pt
->sm_controlPointDragPosX
= (double)(newX1
+ (newWidth
/2.0));
1388 pt
->sm_controlPointDragPosY
= (double)(newY1
+ (newHeight
/2.0));
1389 if (this->GetFixedWidth())
1392 if (this->GetFixedHeight())
1393 newHeight
= bound_y
;
1395 pt
->sm_controlPointDragEndWidth
= newWidth
;
1396 pt
->sm_controlPointDragEndHeight
= newHeight
;
1397 this->GetEventHandler()->OnDrawOutline(dc
, pt
->sm_controlPointDragPosX
, pt
->sm_controlPointDragPosY
, newWidth
, newHeight
);
1401 void wxShape::OnSizingBeginDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int attachment
)
1403 m_canvas
->CaptureMouse();
1405 wxClientDC
dc(GetCanvas());
1406 GetCanvas()->PrepareDC(dc
);
1408 if (pt->m_eraseObject)
1412 dc
.SetLogicalFunction(OGLRBLF
);
1416 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1418 // Choose the 'opposite corner' of the object as the stationary
1419 // point in case this is non-centring resizing.
1420 if (pt
->GetX() < this->GetX())
1421 pt
->sm_controlPointDragStartX
= (double)(this->GetX() + (bound_x
/2.0));
1423 pt
->sm_controlPointDragStartX
= (double)(this->GetX() - (bound_x
/2.0));
1425 if (pt
->GetY() < this->GetY())
1426 pt
->sm_controlPointDragStartY
= (double)(this->GetY() + (bound_y
/2.0));
1428 pt
->sm_controlPointDragStartY
= (double)(this->GetY() - (bound_y
/2.0));
1430 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1431 pt
->sm_controlPointDragStartY
= (double)(this->GetY() - (bound_y
/2.0));
1432 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1433 pt
->sm_controlPointDragStartX
= (double)(this->GetX() - (bound_x
/2.0));
1435 // We may require the old width and height.
1436 pt
->sm_controlPointDragStartWidth
= bound_x
;
1437 pt
->sm_controlPointDragStartHeight
= bound_y
;
1439 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1440 dc
.SetPen(dottedPen
);
1441 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1443 if (this->GetCentreResize())
1445 double new_width
= (double)(2.0*fabs(x
- this->GetX()));
1446 double new_height
= (double)(2.0*fabs(y
- this->GetY()));
1448 // Constrain sizing according to what control point you're dragging
1449 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1451 if (GetMaintainAspectRatio())
1453 new_height
= bound_y
*(new_width
/bound_x
);
1456 new_height
= bound_y
;
1458 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1460 if (GetMaintainAspectRatio())
1462 new_width
= bound_x
*(new_height
/bound_y
);
1465 new_width
= bound_x
;
1467 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& (keys
& KEY_SHIFT
))
1468 new_height
= bound_y
*(new_width
/bound_x
);
1470 if (this->GetFixedWidth())
1471 new_width
= bound_x
;
1473 if (this->GetFixedHeight())
1474 new_height
= bound_y
;
1476 pt
->sm_controlPointDragEndWidth
= new_width
;
1477 pt
->sm_controlPointDragEndHeight
= new_height
;
1478 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1479 new_width
, new_height
);
1483 // Don't maintain the same centre point!
1484 double newX1
= wxMin(pt
->sm_controlPointDragStartX
, x
);
1485 double newY1
= wxMin(pt
->sm_controlPointDragStartY
, y
);
1486 double newX2
= wxMax(pt
->sm_controlPointDragStartX
, x
);
1487 double newY2
= wxMax(pt
->sm_controlPointDragStartY
, y
);
1488 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1490 newY1
= pt
->sm_controlPointDragStartY
;
1491 newY2
= newY1
+ pt
->sm_controlPointDragStartHeight
;
1493 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1495 newX1
= pt
->sm_controlPointDragStartX
;
1496 newX2
= newX1
+ pt
->sm_controlPointDragStartWidth
;
1498 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& ((keys
& KEY_SHIFT
) || GetMaintainAspectRatio()))
1500 double newH
= (double)((newX2
- newX1
)*(pt
->sm_controlPointDragStartHeight
/pt
->sm_controlPointDragStartWidth
));
1501 if (pt
->GetY() > pt
->sm_controlPointDragStartY
)
1502 newY2
= (double)(newY1
+ newH
);
1504 newY1
= (double)(newY2
- newH
);
1506 double newWidth
= (double)(newX2
- newX1
);
1507 double newHeight
= (double)(newY2
- newY1
);
1509 if (pt
->m_type
== CONTROL_POINT_VERTICAL
&& GetMaintainAspectRatio())
1511 newWidth
= bound_x
* (newHeight
/bound_y
) ;
1514 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
&& GetMaintainAspectRatio())
1516 newHeight
= bound_y
* (newWidth
/bound_x
) ;
1519 pt
->sm_controlPointDragPosX
= (double)(newX1
+ (newWidth
/2.0));
1520 pt
->sm_controlPointDragPosY
= (double)(newY1
+ (newHeight
/2.0));
1521 if (this->GetFixedWidth())
1524 if (this->GetFixedHeight())
1525 newHeight
= bound_y
;
1527 pt
->sm_controlPointDragEndWidth
= newWidth
;
1528 pt
->sm_controlPointDragEndHeight
= newHeight
;
1529 this->GetEventHandler()->OnDrawOutline(dc
, pt
->sm_controlPointDragPosX
, pt
->sm_controlPointDragPosY
, newWidth
, newHeight
);
1533 void wxShape::OnSizingEndDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int attachment
)
1535 wxClientDC
dc(GetCanvas());
1536 GetCanvas()->PrepareDC(dc
);
1538 m_canvas
->ReleaseMouse();
1539 dc
.SetLogicalFunction(wxCOPY
);
1541 this->ResetControlPoints();
1545 if (!pt->m_eraseObject)
1549 this->SetSize(pt
->sm_controlPointDragEndWidth
, pt
->sm_controlPointDragEndHeight
);
1551 // The next operation could destroy this control point (it does for label objects,
1552 // via formatting the text), so save all values we're going to use, or
1553 // we'll be accessing garbage.
1554 wxShape
*theObject
= this;
1555 wxShapeCanvas
*theCanvas
= m_canvas
;
1556 bool eraseIt
= pt
->m_eraseObject
;
1558 if (theObject
->GetCentreResize())
1559 theObject
->Move(dc
, theObject
->GetX(), theObject
->GetY());
1561 theObject
->Move(dc
, pt
->sm_controlPointDragPosX
, pt
->sm_controlPointDragPosY
);
1565 theObject->Show(TRUE);
1568 // Recursively redraw links if we have a composite.
1569 if (theObject
->GetChildren().GetCount() > 0)
1570 theObject
->DrawLinks(dc
, -1, TRUE
);
1572 double width
, height
;
1573 theObject
->GetBoundingBoxMax(&width
, &height
);
1574 theObject
->GetEventHandler()->OnEndSize(width
, height
);
1576 if (!theCanvas
->GetQuickEditMode() && eraseIt
) theCanvas
->Redraw(dc
);
1581 // Polygon control points
1583 IMPLEMENT_DYNAMIC_CLASS(wxPolygonControlPoint
, wxControlPoint
)
1585 wxPolygonControlPoint::wxPolygonControlPoint(wxShapeCanvas
*theCanvas
, wxShape
*object
, double size
,
1586 wxRealPoint
*vertex
, double the_xoffset
, double the_yoffset
):
1587 wxControlPoint(theCanvas
, object
, size
, the_xoffset
, the_yoffset
, 0)
1589 m_polygonVertex
= vertex
;
1590 m_originalDistance
= 0.0;
1593 wxPolygonControlPoint::~wxPolygonControlPoint()
1597 // Calculate what new size would be, at end of resize
1598 void wxPolygonControlPoint::CalculateNewSize(double x
, double y
)
1602 GetShape()->GetBoundingBoxMin(&bound_x
, &bound_y
);
1604 double dist
= (double)sqrt((x
- m_shape
->GetX())*(x
- m_shape
->GetX()) +
1605 (y
- m_shape
->GetY())*(y
- m_shape
->GetY()));
1607 m_newSize
.x
= (double)(dist
/this->m_originalDistance
)*this->m_originalSize
.x
;
1608 m_newSize
.y
= (double)(dist
/this->m_originalDistance
)*this->m_originalSize
.y
;
1612 // Implement resizing polygon or moving the vertex.
1613 void wxPolygonControlPoint::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
1615 m_shape
->GetEventHandler()->OnSizingDragLeft(this, draw
, x
, y
, keys
, attachment
);
1618 void wxPolygonControlPoint::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
1620 m_shape
->GetEventHandler()->OnSizingBeginDragLeft(this, x
, y
, keys
, attachment
);
1623 void wxPolygonControlPoint::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
1625 m_shape
->GetEventHandler()->OnSizingEndDragLeft(this, x
, y
, keys
, attachment
);
1628 // Control points ('handles') redirect control to the actual shape, to make it easier
1629 // to override sizing behaviour.
1630 void wxPolygonShape::OnSizingDragLeft(wxControlPoint
* pt
, bool draw
, double x
, double y
, int keys
, int attachment
)
1632 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
1634 wxClientDC
dc(GetCanvas());
1635 GetCanvas()->PrepareDC(dc
);
1637 dc
.SetLogicalFunction(OGLRBLF
);
1639 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1640 dc
.SetPen(dottedPen
);
1641 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1643 if (0) // keys & KEY_CTRL)
1645 // TODO: mend this code. Currently we rely on altering the
1646 // actual points, but we should assume we're not, as per
1647 // the normal sizing case.
1648 m_canvas
->Snap(&x
, &y
);
1651 ppt
->m_polygonVertex
->x
= x
- this->GetX();
1652 ppt
->m_polygonVertex
->y
= y
- this->GetY();
1655 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1656 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1660 ppt
->CalculateNewSize(x
, y
);
1663 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1664 ppt
->GetNewSize().x
, ppt
->GetNewSize().y
);
1667 void wxPolygonShape::OnSizingBeginDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int attachment
)
1669 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
1671 wxClientDC
dc(GetCanvas());
1672 GetCanvas()->PrepareDC(dc
);
1676 dc
.SetLogicalFunction(OGLRBLF
);
1680 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1682 double dist
= (double)sqrt((x
- this->GetX())*(x
- this->GetX()) +
1683 (y
- this->GetY())*(y
- this->GetY()));
1684 ppt
->m_originalDistance
= dist
;
1685 ppt
->m_originalSize
.x
= bound_x
;
1686 ppt
->m_originalSize
.y
= bound_y
;
1688 if (ppt
->m_originalDistance
== 0.0) ppt
->m_originalDistance
= (double) 0.0001;
1690 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1691 dc
.SetPen(dottedPen
);
1692 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1694 if (0) // keys & KEY_CTRL)
1696 // TODO: mend this code. Currently we rely on altering the
1697 // actual points, but we should assume we're not, as per
1698 // the normal sizing case.
1699 m_canvas
->Snap(&x
, &y
);
1702 ppt
->m_polygonVertex
->x
= x
- this->GetX();
1703 ppt
->m_polygonVertex
->y
= y
- this->GetY();
1706 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1707 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1711 ppt
->CalculateNewSize(x
, y
);
1714 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1715 ppt
->GetNewSize().x
, ppt
->GetNewSize().y
);
1717 m_canvas
->CaptureMouse();
1720 void wxPolygonShape::OnSizingEndDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int attachment
)
1722 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
1724 wxClientDC
dc(GetCanvas());
1725 GetCanvas()->PrepareDC(dc
);
1727 m_canvas
->ReleaseMouse();
1728 dc
.SetLogicalFunction(wxCOPY
);
1730 // If we're changing shape, must reset the original points
1731 if (keys
& KEY_CTRL
)
1733 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1734 ((wxPolygonShape
*)this)->UpdateOriginalPoints();
1738 SetSize(ppt
->GetNewSize().x
, ppt
->GetNewSize().y
);
1741 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1742 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1745 this->ResetControlPoints();
1746 this->Move(dc
, this->GetX(), this->GetY());
1747 if (!m_canvas
->GetQuickEditMode()) m_canvas
->Redraw(dc
);
1754 IMPLEMENT_DYNAMIC_CLASS(wxShapeRegion
, wxObject
)
1756 wxShapeRegion::wxShapeRegion()
1758 m_regionText
= wxEmptyString
;
1759 m_font
= g_oglNormalFont
;
1767 m_regionProportionX
= -1.0;
1768 m_regionProportionY
= -1.0;
1769 m_formatMode
= FORMAT_CENTRE_HORIZ
| FORMAT_CENTRE_VERT
;
1770 m_regionName
= wxEmptyString
;
1771 m_textColour
= wxT("BLACK");
1772 m_penColour
= wxT("BLACK");
1773 m_penStyle
= wxSOLID
;
1774 m_actualColourObject
= NULL
;
1775 m_actualPenObject
= NULL
;
1778 wxShapeRegion::wxShapeRegion(wxShapeRegion
& region
)
1780 m_regionText
= region
.m_regionText
;
1781 m_regionName
= region
.m_regionName
;
1782 m_textColour
= region
.m_textColour
;
1784 m_font
= region
.m_font
;
1785 m_minHeight
= region
.m_minHeight
;
1786 m_minWidth
= region
.m_minWidth
;
1787 m_width
= region
.m_width
;
1788 m_height
= region
.m_height
;
1792 m_regionProportionX
= region
.m_regionProportionX
;
1793 m_regionProportionY
= region
.m_regionProportionY
;
1794 m_formatMode
= region
.m_formatMode
;
1795 m_actualColourObject
= NULL
;
1796 m_actualPenObject
= NULL
;
1797 m_penStyle
= region
.m_penStyle
;
1798 m_penColour
= region
.m_penColour
;
1801 wxNode
*node
= region
.m_formattedText
.GetFirst();
1804 wxShapeTextLine
*line
= (wxShapeTextLine
*)node
->GetData();
1805 wxShapeTextLine
*new_line
=
1806 new wxShapeTextLine(line
->GetX(), line
->GetY(), line
->GetText());
1807 m_formattedText
.Append(new_line
);
1808 node
= node
->GetNext();
1812 wxShapeRegion::~wxShapeRegion()
1817 void wxShapeRegion::ClearText()
1819 wxNode
*node
= m_formattedText
.GetFirst();
1822 wxShapeTextLine
*line
= (wxShapeTextLine
*)node
->GetData();
1823 wxNode
*next
= node
->GetNext();
1830 void wxShapeRegion::SetFont(wxFont
*f
)
1835 void wxShapeRegion::SetMinSize(double w
, double h
)
1841 void wxShapeRegion::SetSize(double w
, double h
)
1847 void wxShapeRegion::SetPosition(double xp
, double yp
)
1853 void wxShapeRegion::SetProportions(double xp
, double yp
)
1855 m_regionProportionX
= xp
;
1856 m_regionProportionY
= yp
;
1859 void wxShapeRegion::SetFormatMode(int mode
)
1861 m_formatMode
= mode
;
1864 void wxShapeRegion::SetColour(const wxString
& col
)
1867 m_actualColourObject
= NULL
;
1870 wxColour
*wxShapeRegion::GetActualColourObject()
1872 if (!m_actualColourObject
)
1873 m_actualColourObject
= wxTheColourDatabase
->FindColour(GetColour());
1874 if (!m_actualColourObject
)
1875 m_actualColourObject
= wxBLACK
;
1876 return m_actualColourObject
;
1879 void wxShapeRegion::SetPenColour(const wxString
& col
)
1882 m_actualPenObject
= NULL
;
1885 // Returns NULL if the pen is invisible
1886 // (different to pen being transparent; indicates that
1887 // region boundary should not be drawn.)
1888 wxPen
*wxShapeRegion::GetActualPen()
1890 if (m_actualPenObject
)
1891 return m_actualPenObject
;
1893 if (!m_penColour
) return NULL
;
1894 if (m_penColour
== wxT("Invisible"))
1896 m_actualPenObject
= wxThePenList
->FindOrCreatePen(m_penColour
, 1, m_penStyle
);
1897 return m_actualPenObject
;