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
)
70 m_originalPoints
= the_points
;
72 // Duplicate the list of points
73 m_points
= new wxList
;
75 wxNode
*node
= the_points
->First();
78 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
79 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
80 m_points
->Append((wxObject
*) new_point
);
83 CalculateBoundingBox();
84 m_originalWidth
= m_boundWidth
;
85 m_originalHeight
= m_boundHeight
;
86 SetDefaultRegionSize();
89 wxPolygonShape::~wxPolygonShape()
93 wxNode
*node
= m_points
->First();
96 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
99 node
= m_points
->First();
103 if (m_originalPoints
)
105 wxNode
*node
= m_originalPoints
->First();
108 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
111 node
= m_originalPoints
->First();
113 delete m_originalPoints
;
118 // Width and height. Centre of object is centre of box.
119 void wxPolygonShape::GetBoundingBoxMin(float *width
, float *height
)
121 *width
= m_boundWidth
;
122 *height
= m_boundHeight
;
125 void wxPolygonShape::CalculateBoundingBox()
127 // Calculate bounding box at construction (and presumably resize) time
129 float right
= -10000;
131 float bottom
= -10000;
133 wxNode
*node
= m_points
->First();
136 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
137 if (point
->x
< left
) left
= point
->x
;
138 if (point
->x
> right
) right
= point
->x
;
140 if (point
->y
< top
) top
= point
->y
;
141 if (point
->y
> bottom
) bottom
= point
->y
;
145 m_boundWidth
= right
- left
;
146 m_boundHeight
= bottom
- top
;
149 // Recalculates the centre of the polygon, and
150 // readjusts the point offsets accordingly.
151 // Necessary since the centre of the polygon
152 // is expected to be the real centre of the bounding
154 void wxPolygonShape::CalculatePolygonCentre()
157 float right
= -10000;
159 float bottom
= -10000;
161 wxNode
*node
= m_points
->First();
164 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
165 if (point
->x
< left
) left
= point
->x
;
166 if (point
->x
> right
) right
= point
->x
;
168 if (point
->y
< top
) top
= point
->y
;
169 if (point
->y
> bottom
) bottom
= point
->y
;
173 float bwidth
= right
- left
;
174 float bheight
= bottom
- top
;
176 float newCentreX
= (float)(left
+ (bwidth
/2.0));
177 float newCentreY
= (float)(top
+ (bheight
/2.0));
179 node
= m_points
->First();
182 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
183 point
->x
-= newCentreX
;
184 point
->y
-= newCentreY
;
187 m_xpos
+= newCentreX
;
188 m_ypos
+= newCentreY
;
191 bool PolylineHitTest(float n
, float xvec
[], float yvec
[],
192 float x1
, float y1
, float x2
, float y2
)
196 float lastx
= xvec
[0];
197 float lasty
= yvec
[0];
199 float min_ratio
= 1.0;
204 for (i
= 1; i
< n
; i
++)
206 check_line_intersection(x1
, y1
, x2
, y2
, lastx
, lasty
, xvec
[i
], yvec
[i
],
207 &line_ratio
, &other_ratio
);
208 if (line_ratio
!= 1.0)
210 // sprintf(buf, "Line ratio = %.2f, other ratio = %.2f\n", line_ratio, other_ratio);
211 // ClipsErrorFunction(buf);
215 if (line_ratio
< min_ratio
)
216 min_ratio
= line_ratio
;
219 // Do last (implicit) line if last and first floats are not identical
220 if (!(xvec
[0] == lastx
&& yvec
[0] == lasty
))
222 check_line_intersection(x1
, y1
, x2
, y2
, lastx
, lasty
, xvec
[0], yvec
[0],
223 &line_ratio
, &other_ratio
);
224 if (line_ratio
!= 1.0)
226 // sprintf(buf, "Line ratio = %.2f, other ratio = %.2f\n", line_ratio, other_ratio);
227 // ClipsErrorFunction(buf);
229 if (line_ratio
< min_ratio
)
230 min_ratio
= line_ratio
;
232 // ClipsErrorFunction("\n");
236 bool wxPolygonShape::HitTest(float x
, float y
, int *attachment
, float *distance
)
238 // Imagine four lines radiating from this point. If all of these lines hit the polygon,
239 // we're inside it, otherwise we're not. Obviously we'd need more radiating lines
240 // to be sure of correct results for very strange (concave) shapes.
245 endPointsY
[0] = (float)(y
- 1000.0);
247 endPointsX
[1] = (float)(x
+ 1000.0);
251 endPointsY
[2] = (float)(y
+ 1000.0);
253 endPointsX
[3] = (float)(x
- 1000.0);
256 // Store polygon points in an array
257 int np
= m_points
->Number();
258 float *xpoints
= new float[np
];
259 float *ypoints
= new float[np
];
260 wxNode
*node
= m_points
->First();
264 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
265 xpoints
[i
] = point
->x
+ m_xpos
;
266 ypoints
[i
] = point
->y
+ m_ypos
;
271 // We assume it's inside the polygon UNLESS one or more
272 // lines don't hit the outline.
273 bool isContained
= TRUE
;
276 for (i
= 0; i
< noPoints
; i
++)
278 if (!PolylineHitTest(np
, xpoints
, ypoints
, x
, y
, endPointsX
[i
], endPointsY
[i
]))
283 ClipsErrorFunction("It's a hit!\n");
285 ClipsErrorFunction("No hit.\n");
293 int nearest_attachment
= 0;
295 // If a hit, check the attachment points within the object.
296 int n
= GetNumberOfAttachments();
297 float nearest
= 999999.0;
299 for (i
= 0; i
< n
; i
++)
302 if (GetAttachmentPosition(i
, &xp
, &yp
))
304 float l
= (float)sqrt(((xp
- x
) * (xp
- x
)) +
305 ((yp
- y
) * (yp
- y
)));
309 nearest_attachment
= i
;
313 *attachment
= nearest_attachment
;
318 // Really need to be able to reset the shape! Otherwise, if the
319 // points ever go to zero, we've lost it, and can't resize.
320 void wxPolygonShape::SetSize(float new_width
, float new_height
, bool recursive
)
322 SetAttachmentSize(new_width
, new_height
);
324 // Multiply all points by proportion of new size to old size
325 float x_proportion
= (float)(fabs(new_width
/m_originalWidth
));
326 float y_proportion
= (float)(fabs(new_height
/m_originalHeight
));
328 wxNode
*node
= m_points
->First();
329 wxNode
*original_node
= m_originalPoints
->First();
330 while (node
&& original_node
)
332 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
333 wxRealPoint
*original_point
= (wxRealPoint
*)original_node
->Data();
335 point
->x
= (original_point
->x
* x_proportion
);
336 point
->y
= (original_point
->y
* y_proportion
);
339 original_node
= original_node
->Next();
342 // CalculateBoundingBox();
343 m_boundWidth
= (float)fabs(new_width
);
344 m_boundHeight
= (float)fabs(new_height
);
345 SetDefaultRegionSize();
348 // Make the original points the same as the working points
349 void wxPolygonShape::UpdateOriginalPoints()
351 if (!m_originalPoints
) m_originalPoints
= new wxList
;
352 wxNode
*original_node
= m_originalPoints
->First();
353 while (original_node
)
355 wxNode
*next_node
= original_node
->Next();
356 wxRealPoint
*original_point
= (wxRealPoint
*)original_node
->Data();
357 delete original_point
;
358 delete original_node
;
360 original_node
= next_node
;
363 wxNode
*node
= m_points
->First();
366 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
367 wxRealPoint
*original_point
= new wxRealPoint(point
->x
, point
->y
);
368 m_originalPoints
->Append((wxObject
*) original_point
);
372 CalculateBoundingBox();
373 m_originalWidth
= m_boundWidth
;
374 m_originalHeight
= m_boundHeight
;
377 void wxPolygonShape::AddPolygonPoint(int pos
)
379 wxNode
*node
= m_points
->Nth(pos
);
380 if (!node
) node
= m_points
->First();
381 wxRealPoint
*firstPoint
= (wxRealPoint
*)node
->Data();
383 wxNode
*node2
= m_points
->Nth(pos
+ 1);
384 if (!node2
) node2
= m_points
->First();
385 wxRealPoint
*secondPoint
= (wxRealPoint
*)node2
->Data();
387 float x
= (float)((secondPoint
->x
- firstPoint
->x
)/2.0 + firstPoint
->x
);
388 float y
= (float)((secondPoint
->y
- firstPoint
->y
)/2.0 + firstPoint
->y
);
389 wxRealPoint
*point
= new wxRealPoint(x
, y
);
391 if (pos
>= (m_points
->Number() - 1))
392 m_points
->Append((wxObject
*) point
);
394 m_points
->Insert(node2
, (wxObject
*) point
);
396 UpdateOriginalPoints();
400 DeleteControlPoints();
405 void wxPolygonShape::DeletePolygonPoint(int pos
)
407 wxNode
*node
= m_points
->Nth(pos
);
410 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
413 UpdateOriginalPoints();
416 DeleteControlPoints();
422 // Assume (x1, y1) is centre of box (most generally, line end at box)
423 bool wxPolygonShape::GetPerimeterPoint(float x1
, float y1
,
425 float *x3
, float *y3
)
427 int n
= m_points
->Number();
429 // First check for situation where the line is vertical,
430 // and we would want to connect to a point on that vertical --
431 // find_end_for_polyline can't cope with this (the arrow
432 // gets drawn to the wrong place).
433 if ((!m_attachmentMode
) && (x1
== x2
))
435 // Look for the point we'd be connecting to. This is
437 wxNode
*node
= m_points
->First();
440 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
443 if ((y2
> y1
) && (point
->y
> 0.0))
445 *x3
= point
->x
+ m_xpos
;
446 *y3
= point
->y
+ m_ypos
;
449 else if ((y2
< y1
) && (point
->y
< 0.0))
451 *x3
= point
->x
+ m_xpos
;
452 *y3
= point
->y
+ m_ypos
;
460 float *xpoints
= new float[n
];
461 float *ypoints
= new float[n
];
463 wxNode
*node
= m_points
->First();
467 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
468 xpoints
[i
] = point
->x
+ m_xpos
;
469 ypoints
[i
] = point
->y
+ m_ypos
;
474 wxRealPoint *point = (wxRealPoint *)m_points->First()->Data();
475 xpoints[i] = point->x + m_xpos;
476 ypoints[i] = point->y + m_ypos;
479 find_end_for_polyline(n
, xpoints
, ypoints
,
480 x1
, y1
, x2
, y2
, x3
, y3
);
488 void wxPolygonShape::OnDraw(wxDC
& dc
)
490 int n
= m_points
->Number();
491 wxPoint
*intPoints
= new wxPoint
[n
];
493 for (i
= 0; i
< n
; i
++)
495 wxRealPoint
* point
= (wxRealPoint
*) m_points
->Nth(i
)->Data();
496 intPoints
[i
].x
= (int) point
->x
;
497 intPoints
[i
].y
= (int) point
->y
;
500 if (m_shadowMode
!= SHADOW_NONE
)
503 dc
.SetBrush(m_shadowBrush
);
504 dc
.SetPen(transparent_pen
);
506 dc
.DrawPolygon(n
, intPoints
, m_xpos
+ m_shadowOffsetX
, m_ypos
+ m_shadowOffsetY
);
511 if (m_pen
->GetWidth() == 0)
512 dc
.SetPen(transparent_pen
);
517 dc
.SetBrush(m_brush
);
518 dc
.DrawPolygon(n
, intPoints
, m_xpos
, m_ypos
);
523 void wxPolygonShape::OnDrawOutline(wxDC
& dc
, float x
, float y
, float w
, float h
)
525 dc
.SetBrush(wxTRANSPARENT_BRUSH
);
527 int n
= m_points
->Number();
528 wxPoint
*intPoints
= new wxPoint
[n
];
530 for (i
= 0; i
< n
; i
++)
532 wxRealPoint
* point
= (wxRealPoint
*) m_points
->Nth(i
)->Data();
533 intPoints
[i
].x
= (int) point
->x
;
534 intPoints
[i
].y
= (int) point
->y
;
536 dc
.DrawPolygon(n
, intPoints
, x
, y
);
537 // wxShape::OnDrawOutline(x, y, w, h);
540 // Make as many control points as there are vertices.
541 void wxPolygonShape::MakeControlPoints()
543 wxNode
*node
= m_points
->First();
546 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
547 wxPolygonControlPoint
*control
= new wxPolygonControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
,
548 point
, point
->x
, point
->y
);
549 m_canvas
->AddShape(control
);
550 m_controlPoints
.Append(control
);
555 float maxX, maxY, minX, minY;
557 GetBoundingBoxMax(&maxX, &maxY);
558 GetBoundingBoxMin(&minX, &minY);
560 float widthMin = (float)(minX + CONTROL_POINT_SIZE + 2);
561 float heightMin = (float)(minY + CONTROL_POINT_SIZE + 2);
563 // Offsets from main object
564 float top = (float)(- (heightMin / 2.0));
565 float bottom = (float)(heightMin / 2.0 + (maxY - minY));
566 float left = (float)(- (widthMin / 2.0));
567 float right = (float)(widthMin / 2.0 + (maxX - minX));
569 wxControlPoint *control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, top,
570 CONTROL_POINT_DIAGONAL);
571 m_canvas->AddShape(control);
572 m_controlPoints.Append(control);
574 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, 0, top,
575 CONTROL_POINT_VERTICAL);
576 m_canvas->AddShape(control);
577 m_controlPoints.Append(control);
579 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, top,
580 CONTROL_POINT_DIAGONAL);
581 m_canvas->AddShape(control);
582 m_controlPoints.Append(control);
584 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, 0,
585 CONTROL_POINT_HORIZONTAL);
586 m_canvas->AddShape(control);
587 m_controlPoints.Append(control);
589 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, bottom,
590 CONTROL_POINT_DIAGONAL);
591 m_canvas->AddShape(control);
592 m_controlPoints.Append(control);
594 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, 0, bottom,
595 CONTROL_POINT_VERTICAL);
596 m_canvas->AddShape(control);
597 m_controlPoints.Append(control);
599 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, bottom,
600 CONTROL_POINT_DIAGONAL);
601 m_canvas->AddShape(control);
602 m_controlPoints.Append(control);
604 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, 0,
605 CONTROL_POINT_HORIZONTAL);
606 m_canvas->AddShape(control);
607 m_controlPoints.Append(control);
611 void wxPolygonShape::ResetControlPoints()
613 wxNode
*node
= m_points
->First();
614 wxNode
*controlPointNode
= m_controlPoints
.First();
615 while (node
&& controlPointNode
)
617 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
618 wxPolygonControlPoint
*controlPoint
= (wxPolygonControlPoint
*)controlPointNode
->Data();
620 controlPoint
->m_xoffset
= point
->x
;
621 controlPoint
->m_yoffset
= point
->y
;
622 controlPoint
->m_polygonVertex
= point
;
625 controlPointNode
= controlPointNode
->Next();
629 if (m_controlPoints.Number() < 1)
632 float maxX, maxY, minX, minY;
634 GetBoundingBoxMax(&maxX, &maxY);
635 GetBoundingBoxMin(&minX, &minY);
637 float widthMin = (float)(minX + CONTROL_POINT_SIZE + 2);
638 float heightMin = (float)(minY + CONTROL_POINT_SIZE + 2);
640 // Offsets from main object
641 float top = (float)(- (heightMin / 2.0));
642 float bottom = (float)(heightMin / 2.0 + (maxY - minY));
643 float left = (float)(- (widthMin / 2.0));
644 float right = (float)(widthMin / 2.0 + (maxX - minX));
646 wxNode *node = m_controlPoints.First();
647 wxControlPoint *control = (wxControlPoint *)node->Data();
648 control->xoffset = left; control->yoffset = top;
650 node = node->Next(); control = (wxControlPoint *)node->Data();
651 control->xoffset = 0; control->yoffset = top;
653 node = node->Next(); control = (wxControlPoint *)node->Data();
654 control->xoffset = right; control->yoffset = top;
656 node = node->Next(); control = (wxControlPoint *)node->Data();
657 control->xoffset = right; control->yoffset = 0;
659 node = node->Next(); control = (wxControlPoint *)node->Data();
660 control->xoffset = right; control->yoffset = bottom;
662 node = node->Next(); control = (wxControlPoint *)node->Data();
663 control->xoffset = 0; control->yoffset = bottom;
665 node = node->Next(); control = (wxControlPoint *)node->Data();
666 control->xoffset = left; control->yoffset = bottom;
668 node = node->Next(); control = (wxControlPoint *)node->Data();
669 control->xoffset = left; control->yoffset = 0;
675 void wxPolygonShape::WritePrologAttributes(wxExpr
*clause
)
677 wxShape::WritePrologAttributes(clause
);
679 clause
->AddAttributeValue("x", m_xpos
);
680 clause
->AddAttributeValue("y", m_ypos
);
682 // Make a list of lists for the coordinates
683 wxExpr
*list
= new wxExpr(PrologList
);
684 wxNode
*node
= m_points
->First();
687 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
688 wxExpr
*point_list
= new wxExpr(PrologList
);
689 wxExpr
*x_expr
= new wxExpr((float)point
->x
);
690 wxExpr
*y_expr
= new wxExpr((float)point
->y
);
692 point_list
->Append(x_expr
);
693 point_list
->Append(y_expr
);
694 list
->Append(point_list
);
698 clause
->AddAttributeValue("points", list
);
700 // Save the original (unscaled) points
701 list
= new wxExpr(PrologList
);
702 node
= m_originalPoints
->First();
705 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
706 wxExpr
*point_list
= new wxExpr(PrologList
);
707 wxExpr
*x_expr
= new wxExpr((float) point
->x
);
708 wxExpr
*y_expr
= new wxExpr((float) point
->y
);
709 point_list
->Append(x_expr
);
710 point_list
->Append(y_expr
);
711 list
->Append(point_list
);
715 clause
->AddAttributeValue("m_originalPoints", list
);
718 void wxPolygonShape::ReadPrologAttributes(wxExpr
*clause
)
720 wxShape::ReadPrologAttributes(clause
);
722 // Read a list of lists
723 m_points
= new wxList
;
724 m_originalPoints
= new wxList
;
726 wxExpr
*points_list
= NULL
;
727 clause
->AssignAttributeValue("points", &points_list
);
729 // If no points_list, don't crash!! Assume a diamond instead.
730 float the_height
= 100.0;
731 float the_width
= 100.0;
734 wxRealPoint
*point
= new wxRealPoint(0.0, (-the_height
/2));
735 m_points
->Append((wxObject
*) point
);
737 point
= new wxRealPoint((the_width
/2), 0.0);
738 m_points
->Append((wxObject
*) point
);
740 point
= new wxRealPoint(0.0, (the_height
/2));
741 m_points
->Append((wxObject
*) point
);
743 point
= new wxRealPoint((-the_width
/2), 0.0);
744 m_points
->Append((wxObject
*) point
);
746 point
= new wxRealPoint(0.0, (-the_height
/2));
747 m_points
->Append((wxObject
*) point
);
751 wxExpr
*node
= points_list
->value
.first
;
755 wxExpr
*xexpr
= node
->value
.first
;
756 long x
= xexpr
->IntegerValue();
758 wxExpr
*yexpr
= xexpr
->next
;
759 long y
= yexpr
->IntegerValue();
761 wxRealPoint
*point
= new wxRealPoint((float)x
, (float)y
);
762 m_points
->Append((wxObject
*) point
);
769 clause
->AssignAttributeValue("m_originalPoints", &points_list
);
771 // If no points_list, don't crash!! Assume a diamond instead.
774 wxRealPoint
*point
= new wxRealPoint(0.0, (-the_height
/2));
775 m_originalPoints
->Append((wxObject
*) point
);
777 point
= new wxRealPoint((the_width
/2), 0.0);
778 m_originalPoints
->Append((wxObject
*) point
);
780 point
= new wxRealPoint(0.0, (the_height
/2));
781 m_originalPoints
->Append((wxObject
*) point
);
783 point
= new wxRealPoint((-the_width
/2), 0.0);
784 m_originalPoints
->Append((wxObject
*) point
);
786 point
= new wxRealPoint(0.0, (-the_height
/2));
787 m_originalPoints
->Append((wxObject
*) point
);
789 m_originalWidth
= the_width
;
790 m_originalHeight
= the_height
;
794 wxExpr
*node
= points_list
->value
.first
;
801 wxExpr
*xexpr
= node
->value
.first
;
802 long x
= xexpr
->IntegerValue();
804 wxExpr
*yexpr
= xexpr
->next
;
805 long y
= yexpr
->IntegerValue();
807 wxRealPoint
*point
= new wxRealPoint((float)x
, (float)y
);
808 m_originalPoints
->Append((wxObject
*) point
);
821 m_originalWidth
= max_x
- min_x
;
822 m_originalHeight
= max_y
- min_y
;
825 CalculateBoundingBox();
829 void wxPolygonShape::Copy(wxShape
& copy
)
833 wxASSERT( copy
.IsKindOf(CLASSINFO(wxPolygonShape
)) );
835 wxPolygonShape
& polyCopy
= (wxPolygonShape
&) copy
;
837 if (polyCopy
.m_points
)
838 delete polyCopy
.m_points
;
840 polyCopy
.m_points
= new wxList
;
842 if (polyCopy
.m_originalPoints
)
843 delete polyCopy
.m_originalPoints
;
845 polyCopy
.m_originalPoints
= new wxList
;
847 wxNode
*node
= m_points
->First();
850 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
851 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
852 polyCopy
.m_points
->Append((wxObject
*) new_point
);
855 node
= m_originalPoints
->First();
858 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
859 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
860 polyCopy
.m_originalPoints
->Append((wxObject
*) new_point
);
863 polyCopy
.m_boundWidth
= m_boundWidth
;
864 polyCopy
.m_boundHeight
= m_boundHeight
;
865 polyCopy
.m_originalWidth
= m_originalWidth
;
866 polyCopy
.m_originalHeight
= m_originalHeight
;
869 int wxPolygonShape::GetNumberOfAttachments()
871 int maxN
= (m_points
? (m_points
->Number() - 1) : 0);
872 wxNode
*node
= m_attachmentPoints
.First();
875 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
876 if (point
->m_id
> maxN
)
883 bool wxPolygonShape::GetAttachmentPosition(int attachment
, float *x
, float *y
,
884 int nth
, int no_arcs
, wxLineShape
*line
)
886 if (m_attachmentMode
&& m_points
&& attachment
< m_points
->Number())
888 wxRealPoint
*point
= (wxRealPoint
*)m_points
->Nth(attachment
)->Data();
889 *x
= point
->x
+ m_xpos
;
890 *y
= point
->y
+ m_ypos
;
894 { return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
); }
897 bool wxPolygonShape::AttachmentIsValid(int attachment
)
902 if ((attachment
>= 0) && (attachment
< m_points
->Number()))
905 wxNode
*node
= m_attachmentPoints
.First();
908 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
909 if (point
->m_id
== attachment
)
918 IMPLEMENT_DYNAMIC_CLASS(wxRectangleShape
, wxShape
)
920 wxRectangleShape::wxRectangleShape(float w
, float h
)
922 m_width
= w
; m_height
= h
; m_cornerRadius
= 0.0;
923 SetDefaultRegionSize();
926 void wxRectangleShape::OnDraw(wxDC
& dc
)
928 float x1
= (float)(m_xpos
- m_width
/2.0);
929 float y1
= (float)(m_ypos
- m_height
/2.0);
931 if (m_shadowMode
!= SHADOW_NONE
)
934 dc
.SetBrush(m_shadowBrush
);
935 dc
.SetPen(transparent_pen
);
937 if (m_cornerRadius
!= 0.0)
938 dc
.DrawRoundedRectangle(x1
+ m_shadowOffsetX
, y1
+ m_shadowOffsetY
,
939 m_width
, m_height
, m_cornerRadius
);
941 dc
.DrawRectangle(x1
+ m_shadowOffsetX
, y1
+ m_shadowOffsetY
, m_width
, m_height
);
946 if (m_pen
->GetWidth() == 0)
947 dc
.SetPen(transparent_pen
);
952 dc
.SetBrush(m_brush
);
954 if (m_cornerRadius
!= 0.0)
955 dc
.DrawRoundedRectangle(x1
, y1
, m_width
, m_height
, m_cornerRadius
);
957 dc
.DrawRectangle(x1
, y1
, m_width
, m_height
);
960 void wxRectangleShape::GetBoundingBoxMin(float *the_width
, float *the_height
)
962 *the_width
= m_width
;
963 *the_height
= m_height
;
966 void wxRectangleShape::SetSize(float x
, float y
, bool recursive
)
968 SetAttachmentSize(x
, y
);
969 m_width
= (float)wxMax(x
, 1.0);
970 m_height
= (float)wxMax(y
, 1.0);
971 SetDefaultRegionSize();
974 void wxRectangleShape::SetCornerRadius(float rad
)
976 m_cornerRadius
= rad
;
979 // Assume (x1, y1) is centre of box (most generally, line end at box)
980 bool wxRectangleShape::GetPerimeterPoint(float x1
, float y1
,
982 float *x3
, float *y3
)
984 float bound_x
, bound_y
;
985 GetBoundingBoxMax(&bound_x
, &bound_y
);
986 find_end_for_box(bound_x
, bound_y
, m_xpos
, m_ypos
, x2
, y2
, x3
, y3
);
992 void wxRectangleShape::WritePrologAttributes(wxExpr
*clause
)
994 wxShape::WritePrologAttributes(clause
);
995 clause
->AddAttributeValue("x", m_xpos
);
996 clause
->AddAttributeValue("y", m_ypos
);
998 clause
->AddAttributeValue("width", m_width
);
999 clause
->AddAttributeValue("height", m_height
);
1000 if (m_cornerRadius
!= 0.0)
1001 clause
->AddAttributeValue("corner", m_cornerRadius
);
1004 void wxRectangleShape::ReadPrologAttributes(wxExpr
*clause
)
1006 wxShape::ReadPrologAttributes(clause
);
1007 clause
->AssignAttributeValue("width", &m_width
);
1008 clause
->AssignAttributeValue("height", &m_height
);
1009 clause
->AssignAttributeValue("corner", &m_cornerRadius
);
1011 // In case we're reading an old file, set the region's size
1012 if (m_regions
.Number() == 1)
1014 wxShapeRegion
*region
= (wxShapeRegion
*)m_regions
.First()->Data();
1015 region
->SetSize(m_width
, m_height
);
1020 void wxRectangleShape::Copy(wxShape
& copy
)
1022 wxShape::Copy(copy
);
1024 wxASSERT( copy
.IsKindOf(CLASSINFO(wxRectangleShape
)) );
1026 wxRectangleShape
& rectCopy
= (wxRectangleShape
&) copy
;
1027 rectCopy
.m_width
= m_width
;
1028 rectCopy
.m_height
= m_height
;
1029 rectCopy
.m_cornerRadius
= m_cornerRadius
;
1032 int wxRectangleShape::GetNumberOfAttachments()
1034 return wxShape::GetNumberOfAttachments();
1037 // There are 4 attachment points on a rectangle - 0 = top, 1 = right, 2 = bottom,
1039 bool wxRectangleShape::GetAttachmentPosition(int attachment
, float *x
, float *y
,
1040 int nth
, int no_arcs
, wxLineShape
*line
)
1042 if (m_attachmentMode
)
1044 float top
= (float)(m_ypos
+ m_height
/2.0);
1045 float bottom
= (float)(m_ypos
- m_height
/2.0);
1046 float left
= (float)(m_xpos
- m_width
/2.0);
1047 float right
= (float)(m_xpos
+ m_width
/2.0);
1049 bool isEnd
= (line
&& line
->IsEnd(this));
1055 if (m_spaceAttachments
)
1057 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
1059 // Align line according to the next handle along
1060 wxRealPoint
*point
= line
->GetNextControlPoint(this);
1061 if (point
->x
< left
)
1063 else if (point
->x
> right
)
1069 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
1079 if (m_spaceAttachments
)
1081 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
1083 // Align line according to the next handle along
1084 wxRealPoint
*point
= line
->GetNextControlPoint(this);
1085 if (point
->y
< bottom
)
1087 else if (point
->y
> top
)
1093 *y
= bottom
+ (nth
+ 1)*m_height
/(no_arcs
+ 1);
1100 if (m_spaceAttachments
)
1102 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
1104 // Align line according to the next handle along
1105 wxRealPoint
*point
= line
->GetNextControlPoint(this);
1106 if (point
->x
< left
)
1108 else if (point
->x
> right
)
1114 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
1123 if (m_spaceAttachments
)
1125 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
1127 // Align line according to the next handle along
1128 wxRealPoint
*point
= line
->GetNextControlPoint(this);
1129 if (point
->y
< bottom
)
1131 else if (point
->y
> top
)
1137 *y
= bottom
+ (nth
+ 1)*m_height
/(no_arcs
+ 1);
1144 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
1151 { *x
= m_xpos
; *y
= m_ypos
; return TRUE
; }
1154 // Text object (no box)
1156 IMPLEMENT_DYNAMIC_CLASS(wxTextShape
, wxRectangleShape
)
1158 wxTextShape::wxTextShape(float width
, float height
):
1159 wxRectangleShape(width
, height
)
1163 void wxTextShape::OnDraw(wxDC
& dc
)
1167 void wxTextShape::Copy(wxShape
& copy
)
1169 wxRectangleShape::Copy(copy
);
1173 void wxTextShape::WritePrologAttributes(wxExpr
*clause
)
1175 wxRectangleShape::WritePrologAttributes(clause
);
1181 IMPLEMENT_DYNAMIC_CLASS(wxEllipseShape
, wxShape
)
1183 wxEllipseShape::wxEllipseShape(float w
, float h
)
1185 m_width
= w
; m_height
= h
;
1186 SetDefaultRegionSize();
1189 void wxEllipseShape::GetBoundingBoxMin(float *w
, float *h
)
1191 *w
= m_width
; *h
= m_height
;
1194 bool wxEllipseShape::GetPerimeterPoint(float x1
, float y1
,
1196 float *x3
, float *y3
)
1198 float bound_x
, bound_y
;
1199 GetBoundingBoxMax(&bound_x
, &bound_y
);
1201 // find_end_for_box(bound_x, bound_y, m_xpos, m_ypos, x2, y2, x3, y3);
1202 draw_arc_to_ellipse(m_xpos
, m_ypos
, bound_x
, bound_y
, x2
, y2
, x1
, y1
, x3
, y3
);
1207 void wxEllipseShape::OnDraw(wxDC
& dc
)
1209 if (m_shadowMode
!= SHADOW_NONE
)
1212 dc
.SetBrush(m_shadowBrush
);
1213 dc
.SetPen(transparent_pen
);
1214 dc
.DrawEllipse((m_xpos
- GetWidth()/2) + m_shadowOffsetX
,
1215 (m_ypos
- GetHeight()/2) + m_shadowOffsetY
,
1216 GetWidth(), GetHeight());
1221 if (m_pen
->GetWidth() == 0)
1222 dc
.SetPen(transparent_pen
);
1227 dc
.SetBrush(m_brush
);
1228 dc
.DrawEllipse((m_xpos
- GetWidth()/2), (m_ypos
- GetHeight()/2), GetWidth(), GetHeight());
1231 void wxEllipseShape::SetSize(float x
, float y
, bool recursive
)
1233 SetAttachmentSize(x
, y
);
1236 SetDefaultRegionSize();
1240 void wxEllipseShape::WritePrologAttributes(wxExpr
*clause
)
1242 wxShape::WritePrologAttributes(clause
);
1243 clause
->AddAttributeValue("x", m_xpos
);
1244 clause
->AddAttributeValue("y", m_ypos
);
1246 clause
->AddAttributeValue("width", m_width
);
1247 clause
->AddAttributeValue("height", m_height
);
1250 void wxEllipseShape::ReadPrologAttributes(wxExpr
*clause
)
1252 wxShape::ReadPrologAttributes(clause
);
1253 clause
->AssignAttributeValue("width", &m_width
);
1254 clause
->AssignAttributeValue("height", &m_height
);
1256 // In case we're reading an old file, set the region's size
1257 if (m_regions
.Number() == 1)
1259 wxShapeRegion
*region
= (wxShapeRegion
*)m_regions
.First()->Data();
1260 region
->SetSize(m_width
, m_height
);
1265 void wxEllipseShape::Copy(wxShape
& copy
)
1267 wxShape::Copy(copy
);
1269 wxASSERT( copy
.IsKindOf(CLASSINFO(wxEllipseShape
)) );
1271 wxEllipseShape
& ellipseCopy
= (wxEllipseShape
&) copy
;
1273 ellipseCopy
.m_width
= m_width
;
1274 ellipseCopy
.m_height
= m_height
;
1277 int wxEllipseShape::GetNumberOfAttachments()
1279 return wxShape::GetNumberOfAttachments();
1282 // There are 4 attachment points on an ellipse - 0 = top, 1 = right, 2 = bottom,
1284 bool wxEllipseShape::GetAttachmentPosition(int attachment
, float *x
, float *y
,
1285 int nth
, int no_arcs
, wxLineShape
*line
)
1287 if (m_attachmentMode
)
1289 float top
= (float)(m_ypos
+ m_height
/2.0);
1290 float bottom
= (float)(m_ypos
- m_height
/2.0);
1291 float left
= (float)(m_xpos
- m_width
/2.0);
1292 float right
= (float)(m_xpos
+ m_width
/2.0);
1297 if (m_spaceAttachments
)
1298 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
1301 // We now have the point on the bounding box: but get the point on the ellipse
1302 // by imagining a vertical line from (*x, m_ypos - m_height- 500) to (*x, m_ypos) intersecting
1304 draw_arc_to_ellipse(m_xpos
, m_ypos
, m_width
, m_height
, *x
, (float)(m_ypos
-m_height
-500), *x
, m_ypos
, x
, y
);
1310 if (m_spaceAttachments
)
1311 *y
= bottom
+ (nth
+ 1)*m_height
/(no_arcs
+ 1);
1313 draw_arc_to_ellipse(m_xpos
, m_ypos
, m_width
, m_height
, (float)(m_xpos
+m_width
+500), *y
, m_xpos
, *y
, x
, y
);
1318 if (m_spaceAttachments
)
1319 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
1322 draw_arc_to_ellipse(m_xpos
, m_ypos
, m_width
, m_height
, *x
, (float)(m_ypos
+m_height
+500), *x
, m_ypos
, x
, y
);
1328 if (m_spaceAttachments
)
1329 *y
= bottom
+ (nth
+ 1)*m_height
/(no_arcs
+ 1);
1331 draw_arc_to_ellipse(m_xpos
, m_ypos
, m_width
, m_height
, (float)(m_xpos
-m_width
-500), *y
, m_xpos
, *y
, x
, y
);
1336 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
1343 { *x
= m_xpos
; *y
= m_ypos
; return TRUE
; }
1348 IMPLEMENT_DYNAMIC_CLASS(wxCircleShape
, wxEllipseShape
)
1350 wxCircleShape::wxCircleShape(float diameter
):wxEllipseShape(diameter
, diameter
)
1354 void wxCircleShape::Copy(wxShape
& copy
)
1356 wxEllipseShape::Copy(copy
);
1359 bool wxCircleShape::GetPerimeterPoint(float x1
, float y1
,
1361 float *x3
, float *y3
)
1363 find_end_for_circle(m_width
/2,
1364 m_xpos
, m_ypos
, // Centre of circle
1365 x2
, y2
, // Other end of line
1373 float wxControlPoint::controlPointDragStartX
= 0.0;
1374 float wxControlPoint::controlPointDragStartY
= 0.0;
1375 float wxControlPoint::controlPointDragStartWidth
= 0.0;
1376 float wxControlPoint::controlPointDragStartHeight
= 0.0;
1377 float wxControlPoint::controlPointDragEndWidth
= 0.0;
1378 float wxControlPoint::controlPointDragEndHeight
= 0.0;
1379 float wxControlPoint::controlPointDragPosX
= 0.0;
1380 float wxControlPoint::controlPointDragPosY
= 0.0;
1382 IMPLEMENT_DYNAMIC_CLASS(wxControlPoint
, wxRectangleShape
)
1384 wxControlPoint::wxControlPoint(wxShapeCanvas
*theCanvas
, wxShape
*object
, float size
, float the_xoffset
, float the_yoffset
, int the_type
):wxRectangleShape(size
, size
)
1386 m_canvas
= theCanvas
;
1388 m_xoffset
= the_xoffset
;
1389 m_yoffset
= the_yoffset
;
1391 SetPen(black_foreground_pen
);
1392 SetBrush(wxBLACK_BRUSH
);
1395 m_eraseObject
= TRUE
;
1398 wxControlPoint::~wxControlPoint()
1402 // Don't even attempt to draw any text - waste of time!
1403 void wxControlPoint::OnDrawContents(wxDC
& dc
)
1407 void wxControlPoint::OnDraw(wxDC
& dc
)
1409 m_xpos
= m_shape
->GetX() + m_xoffset
;
1410 m_ypos
= m_shape
->GetY() + m_yoffset
;
1411 wxRectangleShape::OnDraw(dc
);
1414 void wxControlPoint::OnErase(wxDC
& dc
)
1416 wxRectangleShape::OnErase(dc
);
1419 // Implement resizing of canvas object
1420 void wxControlPoint::OnDragLeft(bool draw
, float x
, float y
, int keys
, int attachment
)
1422 m_shape
->GetEventHandler()->OnSizingDragLeft(this, draw
, x
, y
, keys
, attachment
);
1425 void wxControlPoint::OnBeginDragLeft(float x
, float y
, int keys
, int attachment
)
1427 m_shape
->GetEventHandler()->OnSizingBeginDragLeft(this, x
, y
, keys
, attachment
);
1430 void wxControlPoint::OnEndDragLeft(float x
, float y
, int keys
, int attachment
)
1432 m_shape
->GetEventHandler()->OnSizingEndDragLeft(this, x
, y
, keys
, attachment
);
1435 int wxControlPoint::GetNumberOfAttachments()
1440 bool wxControlPoint::GetAttachmentPosition(int attachment
, float *x
, float *y
,
1441 int nth
, int no_arcs
, wxLineShape
*line
)
1443 *x
= m_xpos
; *y
= m_ypos
;
1447 // Control points ('handles') redirect control to the actual shape, to make it easier
1448 // to override sizing behaviour.
1449 void wxShape::OnSizingDragLeft(wxControlPoint
* pt
, bool draw
, float x
, float y
, int keys
, int attachment
)
1453 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1455 wxClientDC
dc(GetCanvas());
1456 GetCanvas()->PrepareDC(dc
);
1458 dc
.SetLogicalFunction(wxXOR
);
1460 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1461 dc
.SetPen(dottedPen
);
1462 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1464 if (this->GetCentreResize())
1466 // Maintain the same centre point.
1467 float new_width
= (float)(2.0*fabs(x
- this->GetX()));
1468 float new_height
= (float)(2.0*fabs(y
- this->GetY()));
1470 // Constrain sizing according to what control point you're dragging
1471 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1472 new_height
= bound_y
;
1473 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1474 new_width
= bound_x
;
1475 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& (keys
& KEY_SHIFT
))
1476 new_height
= bound_y
*(new_width
/bound_x
);
1478 if (this->GetFixedWidth())
1479 new_width
= bound_x
;
1481 if (this->GetFixedHeight())
1482 new_height
= bound_y
;
1484 pt
->controlPointDragEndWidth
= new_width
;
1485 pt
->controlPointDragEndHeight
= new_height
;
1487 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1488 new_width
, new_height
);
1492 // Don't maintain the same centre point!
1493 float newX1
= wxMin(pt
->controlPointDragStartX
, x
);
1494 float newY1
= wxMin(pt
->controlPointDragStartY
, y
);
1495 float newX2
= wxMax(pt
->controlPointDragStartX
, x
);
1496 float newY2
= wxMax(pt
->controlPointDragStartY
, y
);
1497 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1499 newY1
= pt
->controlPointDragStartY
;
1500 newY2
= newY1
+ pt
->controlPointDragStartHeight
;
1502 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1504 newX1
= pt
->controlPointDragStartX
;
1505 newX2
= newX1
+ pt
->controlPointDragStartWidth
;
1507 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& (keys
& KEY_SHIFT
))
1509 float newH
= (float)((newX2
- newX1
)*(pt
->controlPointDragStartHeight
/pt
->controlPointDragStartWidth
));
1510 if (GetY() > pt
->controlPointDragStartY
)
1511 newY2
= (float)(newY1
+ newH
);
1513 newY1
= (float)(newY2
- newH
);
1515 float newWidth
= (float)(newX2
- newX1
);
1516 float newHeight
= (float)(newY2
- newY1
);
1518 pt
->controlPointDragPosX
= (float)(newX1
+ (newWidth
/2.0));
1519 pt
->controlPointDragPosY
= (float)(newY1
+ (newHeight
/2.0));
1520 if (this->GetFixedWidth())
1523 if (this->GetFixedHeight())
1524 newHeight
= bound_y
;
1526 pt
->controlPointDragEndWidth
= newWidth
;
1527 pt
->controlPointDragEndHeight
= newHeight
;
1528 this->GetEventHandler()->OnDrawOutline(dc
, pt
->controlPointDragPosX
, pt
->controlPointDragPosY
, newWidth
, newHeight
);
1532 void wxShape::OnSizingBeginDragLeft(wxControlPoint
* pt
, float x
, float y
, int keys
, int attachment
)
1534 m_canvas
->CaptureMouse();
1536 wxClientDC
dc(GetCanvas());
1537 GetCanvas()->PrepareDC(dc
);
1539 if (pt
->m_eraseObject
)
1542 dc
.SetLogicalFunction(wxXOR
);
1546 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1548 // Choose the 'opposite corner' of the object as the stationary
1549 // point in case this is non-centring resizing.
1550 if (pt
->GetX() < this->GetX())
1551 pt
->controlPointDragStartX
= (float)(this->GetX() + (bound_x
/2.0));
1553 pt
->controlPointDragStartX
= (float)(this->GetX() - (bound_x
/2.0));
1555 if (pt
->GetY() < this->GetY())
1556 pt
->controlPointDragStartY
= (float)(this->GetY() + (bound_y
/2.0));
1558 pt
->controlPointDragStartY
= (float)(this->GetY() - (bound_y
/2.0));
1560 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1561 pt
->controlPointDragStartY
= (float)(this->GetY() - (bound_y
/2.0));
1562 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1563 pt
->controlPointDragStartX
= (float)(this->GetX() - (bound_x
/2.0));
1565 // We may require the old width and height.
1566 pt
->controlPointDragStartWidth
= bound_x
;
1567 pt
->controlPointDragStartHeight
= bound_y
;
1569 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1570 dc
.SetPen(dottedPen
);
1571 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1573 if (this->GetCentreResize())
1575 float new_width
= (float)(2.0*fabs(x
- this->GetX()));
1576 float new_height
= (float)(2.0*fabs(y
- this->GetY()));
1578 // Constrain sizing according to what control point you're dragging
1579 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1580 new_height
= bound_y
;
1581 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1582 new_width
= bound_x
;
1583 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& (keys
& KEY_SHIFT
))
1584 new_height
= bound_y
*(new_width
/bound_x
);
1586 if (this->GetFixedWidth())
1587 new_width
= bound_x
;
1589 if (this->GetFixedHeight())
1590 new_height
= bound_y
;
1592 pt
->controlPointDragEndWidth
= new_width
;
1593 pt
->controlPointDragEndHeight
= new_height
;
1594 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(),
1595 new_width
, new_height
);
1599 // Don't maintain the same centre point!
1600 float newX1
= wxMin(pt
->controlPointDragStartX
, x
);
1601 float newY1
= wxMin(pt
->controlPointDragStartY
, y
);
1602 float newX2
= wxMax(pt
->controlPointDragStartX
, x
);
1603 float newY2
= wxMax(pt
->controlPointDragStartY
, y
);
1604 if (pt
->m_type
== CONTROL_POINT_HORIZONTAL
)
1606 newY1
= pt
->controlPointDragStartY
;
1607 newY2
= newY1
+ pt
->controlPointDragStartHeight
;
1609 else if (pt
->m_type
== CONTROL_POINT_VERTICAL
)
1611 newX1
= pt
->controlPointDragStartX
;
1612 newX2
= newX1
+ pt
->controlPointDragStartWidth
;
1614 else if (pt
->m_type
== CONTROL_POINT_DIAGONAL
&& (keys
& KEY_SHIFT
))
1616 float newH
= (float)((newX2
- newX1
)*(pt
->controlPointDragStartHeight
/pt
->controlPointDragStartWidth
));
1617 if (pt
->GetY() > pt
->controlPointDragStartY
)
1618 newY2
= (float)(newY1
+ newH
);
1620 newY1
= (float)(newY2
- newH
);
1622 float newWidth
= (float)(newX2
- newX1
);
1623 float newHeight
= (float)(newY2
- newY1
);
1625 pt
->controlPointDragPosX
= (float)(newX1
+ (newWidth
/2.0));
1626 pt
->controlPointDragPosY
= (float)(newY1
+ (newHeight
/2.0));
1627 if (this->GetFixedWidth())
1630 if (this->GetFixedHeight())
1631 newHeight
= bound_y
;
1633 pt
->controlPointDragEndWidth
= newWidth
;
1634 pt
->controlPointDragEndHeight
= newHeight
;
1635 this->GetEventHandler()->OnDrawOutline(dc
, pt
->controlPointDragPosX
, pt
->controlPointDragPosY
, newWidth
, newHeight
);
1639 void wxShape::OnSizingEndDragLeft(wxControlPoint
* pt
, float x
, float y
, int keys
, int attachment
)
1641 wxClientDC
dc(GetCanvas());
1642 GetCanvas()->PrepareDC(dc
);
1644 m_canvas
->ReleaseMouse();
1645 dc
.SetLogicalFunction(wxCOPY
);
1647 this->ResetControlPoints();
1649 if (!pt
->m_eraseObject
)
1652 this->SetSize(pt
->controlPointDragEndWidth
, pt
->controlPointDragEndHeight
);
1654 // The next operation could destroy this control point (it does for label objects,
1655 // via formatting the text), so save all values we're going to use, or
1656 // we'll be accessing garbage.
1657 wxShape
*theObject
= this;
1658 wxShapeCanvas
*theCanvas
= m_canvas
;
1659 bool eraseIt
= pt
->m_eraseObject
;
1661 if (theObject
->GetCentreResize())
1662 theObject
->Move(dc
, theObject
->GetX(), theObject
->GetY());
1664 theObject
->Move(dc
, pt
->controlPointDragPosX
, pt
->controlPointDragPosY
);
1667 theObject
->Show(TRUE
);
1669 // Recursively redraw links if we have a composite.
1670 if (theObject
->GetChildren().Number() > 0)
1671 theObject
->DrawLinks(dc
, -1, TRUE
);
1673 float width
, height
;
1674 theObject
->GetBoundingBoxMax(&width
, &height
);
1675 theObject
->GetEventHandler()->OnEndSize(width
, height
);
1677 if (!theCanvas
->GetQuickEditMode() && eraseIt
) theCanvas
->Redraw(dc
);
1682 // Polygon control points
1684 IMPLEMENT_DYNAMIC_CLASS(wxPolygonControlPoint
, wxControlPoint
)
1686 wxPolygonControlPoint::wxPolygonControlPoint(wxShapeCanvas
*theCanvas
, wxShape
*object
, float size
,
1687 wxRealPoint
*vertex
, float the_xoffset
, float the_yoffset
):
1688 wxControlPoint(theCanvas
, object
, size
, the_xoffset
, the_yoffset
, 0)
1690 m_polygonVertex
= vertex
;
1691 m_originalDistance
= 0.0;
1694 wxPolygonControlPoint::~wxPolygonControlPoint()
1698 // Implement resizing polygon or moving the vertex.
1699 void wxPolygonControlPoint::OnDragLeft(bool draw
, float x
, float y
, int keys
, int attachment
)
1701 m_shape
->GetEventHandler()->OnSizingDragLeft(this, draw
, x
, y
, keys
, attachment
);
1704 void wxPolygonControlPoint::OnBeginDragLeft(float x
, float y
, int keys
, int attachment
)
1706 m_shape
->GetEventHandler()->OnSizingBeginDragLeft(this, x
, y
, keys
, attachment
);
1709 void wxPolygonControlPoint::OnEndDragLeft(float x
, float y
, int keys
, int attachment
)
1711 m_shape
->GetEventHandler()->OnSizingEndDragLeft(this, x
, y
, keys
, attachment
);
1714 // Control points ('handles') redirect control to the actual shape, to make it easier
1715 // to override sizing behaviour.
1716 void wxPolygonShape::OnSizingDragLeft(wxControlPoint
* pt
, bool draw
, float x
, float y
, int keys
, int attachment
)
1718 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
1720 wxClientDC
dc(GetCanvas());
1721 GetCanvas()->PrepareDC(dc
);
1723 dc
.SetLogicalFunction(wxXOR
);
1725 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1726 dc
.SetPen(dottedPen
);
1727 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1731 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1733 float new_width = (float)(2.0*fabs(x - this->GetX()));
1734 float new_height = (float)(2.0*fabs(y - this->GetY()));
1736 float dist
= (float)sqrt((x
- this->GetX())*(x
- this->GetX()) +
1737 (y
- this->GetY())*(y
- this->GetY()));
1739 if (keys
& KEY_CTRL
)
1741 m_canvas
->Snap(&x
, &y
);
1744 ppt
->m_polygonVertex
->x
= x
- this->GetX();
1745 ppt
->m_polygonVertex
->y
= y
- this->GetY();
1748 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1749 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1753 float new_width
= (float)(dist
/ppt
->m_originalDistance
)*ppt
->m_originalSize
.x
;
1754 float new_height
= (float)(dist
/ppt
->m_originalDistance
)*ppt
->m_originalSize
.y
;
1756 // Non-recursive SetSize for speed
1757 this->SetSize(new_width
, new_height
, FALSE
);
1760 this->GetBoundingBoxMax(&w
, &h
);
1761 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(), w
, h
);
1764 void wxPolygonShape::OnSizingBeginDragLeft(wxControlPoint
* pt
, float x
, float y
, int keys
, int attachment
)
1766 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
1768 wxClientDC
dc(GetCanvas());
1769 GetCanvas()->PrepareDC(dc
);
1773 dc
.SetLogicalFunction(wxXOR
);
1777 this->GetBoundingBoxMin(&bound_x
, &bound_y
);
1779 float dist
= (float)sqrt((x
- this->GetX())*(x
- this->GetX()) +
1780 (y
- this->GetY())*(y
- this->GetY()));
1782 ppt
->m_originalDistance
= dist
;
1783 ppt
->m_originalSize
.x
= bound_x
;
1784 ppt
->m_originalSize
.y
= bound_y
;
1786 if (ppt
->m_originalDistance
== 0.0) ppt
->m_originalDistance
= (float) 0.0001;
1788 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1789 dc
.SetPen(dottedPen
);
1790 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1792 if (keys
& KEY_CTRL
)
1794 m_canvas
->Snap(&x
, &y
);
1797 ppt
->m_polygonVertex
->x
= x
- this->GetX();
1798 ppt
->m_polygonVertex
->y
= y
- this->GetY();
1801 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1802 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1806 float new_width
= (float)(dist
/ppt
->m_originalDistance
)*ppt
->m_originalSize
.x
;
1807 float new_height
= (float)(dist
/ppt
->m_originalDistance
)*ppt
->m_originalSize
.y
;
1809 // Non-recursive SetSize for speed
1810 this->SetSize(new_width
, new_height
, FALSE
);
1814 this->GetBoundingBoxMax(&w
, &h
);
1815 this->GetEventHandler()->OnDrawOutline(dc
, this->GetX(), this->GetY(), w
, h
);
1817 m_canvas
->CaptureMouse();
1820 void wxPolygonShape::OnSizingEndDragLeft(wxControlPoint
* pt
, float x
, float y
, int keys
, int attachment
)
1822 wxClientDC
dc(GetCanvas());
1823 GetCanvas()->PrepareDC(dc
);
1825 m_canvas
->ReleaseMouse();
1826 dc
.SetLogicalFunction(wxCOPY
);
1828 // If we're changing shape, must reset the original points
1829 if (keys
& KEY_CTRL
)
1831 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1832 ((wxPolygonShape
*)this)->UpdateOriginalPoints();
1835 ((wxPolygonShape
*)this)->CalculateBoundingBox();
1836 ((wxPolygonShape
*)this)->CalculatePolygonCentre();
1839 this->ResetControlPoints();
1840 this->Move(dc
, this->GetX(), this->GetY());
1841 if (!m_canvas
->GetQuickEditMode()) m_canvas
->Redraw(dc
);
1848 IMPLEMENT_DYNAMIC_CLASS(wxShapeRegion
, wxObject
)
1850 wxShapeRegion::wxShapeRegion()
1853 m_font
= g_oglNormalFont
;
1861 m_regionProportionX
= -1.0;
1862 m_regionProportionY
= -1.0;
1863 m_formatMode
= FORMAT_CENTRE_HORIZ
| FORMAT_CENTRE_VERT
;
1865 m_textColour
= "BLACK";
1866 m_penColour
= "BLACK";
1867 m_penStyle
= wxSOLID
;
1868 m_actualColourObject
= NULL
;
1869 m_actualPenObject
= NULL
;
1872 wxShapeRegion::wxShapeRegion(wxShapeRegion
& region
)
1874 m_regionText
= region
.m_regionText
;
1875 m_regionName
= region
.m_regionName
;
1876 m_textColour
= region
.m_textColour
;
1878 m_font
= region
.m_font
;
1879 m_minHeight
= region
.m_minHeight
;
1880 m_minWidth
= region
.m_minWidth
;
1881 m_width
= region
.m_width
;
1882 m_height
= region
.m_height
;
1886 m_regionProportionX
= region
.m_regionProportionX
;
1887 m_regionProportionY
= region
.m_regionProportionY
;
1888 m_formatMode
= region
.m_formatMode
;
1889 m_actualColourObject
= NULL
;
1890 m_actualPenObject
= NULL
;
1891 m_penStyle
= region
.m_penStyle
;
1892 m_penColour
= region
.m_penColour
;
1895 wxNode
*node
= region
.m_formattedText
.First();
1898 wxShapeTextLine
*line
= (wxShapeTextLine
*)node
->Data();
1899 wxShapeTextLine
*new_line
=
1900 new wxShapeTextLine(line
->GetX(), line
->GetY(), line
->GetText());
1901 m_formattedText
.Append(new_line
);
1902 node
= node
->Next();
1906 wxShapeRegion::~wxShapeRegion()
1911 void wxShapeRegion::ClearText()
1913 wxNode
*node
= m_formattedText
.First();
1916 wxShapeTextLine
*line
= (wxShapeTextLine
*)node
->Data();
1917 wxNode
*next
= node
->Next();
1924 void wxShapeRegion::SetFont(wxFont
*f
)
1929 void wxShapeRegion::SetMinSize(float w
, float h
)
1935 void wxShapeRegion::SetSize(float w
, float h
)
1941 void wxShapeRegion::SetPosition(float xp
, float yp
)
1947 void wxShapeRegion::SetProportions(float xp
, float yp
)
1949 m_regionProportionX
= xp
;
1950 m_regionProportionY
= yp
;
1953 void wxShapeRegion::SetFormatMode(int mode
)
1955 m_formatMode
= mode
;
1958 void wxShapeRegion::SetColour(const wxString
& col
)
1961 m_actualColourObject
= NULL
;
1964 wxColour
*wxShapeRegion::GetActualColourObject()
1966 if (!m_actualColourObject
)
1967 m_actualColourObject
= wxTheColourDatabase
->FindColour(GetColour());
1968 if (!m_actualColourObject
)
1969 m_actualColourObject
= wxBLACK
;
1970 return m_actualColourObject
;
1973 void wxShapeRegion::SetPenColour(const wxString
& col
)
1976 m_actualPenObject
= NULL
;
1979 // Returns NULL if the pen is invisible
1980 // (different to pen being transparent; indicates that
1981 // region boundary should not be drawn.)
1982 wxPen
*wxShapeRegion::GetActualPen()
1984 if (m_actualPenObject
)
1985 return m_actualPenObject
;
1987 if (!m_penColour
) return NULL
;
1988 if (m_penColour
== "Invisible")
1990 m_actualPenObject
= wxThePenList
->FindOrCreatePen(m_penColour
, 1, m_penStyle
);
1991 return m_actualPenObject
;