1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxLineShape
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "lines.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include <wx/wxprec.h>
28 #include <wx/wxexpr.h>
49 IMPLEMENT_DYNAMIC_CLASS(wxLineShape
, wxShape
)
51 wxLineShape::wxLineShape()
53 m_sensitivity
= OP_CLICK_LEFT
| OP_CLICK_RIGHT
;
58 m_actualTextWidth = 0.0;
59 m_actualTextHeight = 0.0;
64 m_arrowSpacing
= 5.0; // For the moment, don't bother saving this to file.
65 m_ignoreArrowOffsets
= FALSE
;
67 m_maintainStraightLines
= FALSE
;
71 m_lineControlPoints
= NULL
;
73 // Clear any existing regions (created in an earlier constructor)
74 // and make the three line regions.
76 wxShapeRegion
*newRegion
= new wxShapeRegion
;
77 newRegion
->SetName("Middle");
78 newRegion
->SetSize(150, 50);
79 m_regions
.Append((wxObject
*)newRegion
);
81 newRegion
= new wxShapeRegion
;
82 newRegion
->SetName("Start");
83 newRegion
->SetSize(150, 50);
84 m_regions
.Append((wxObject
*)newRegion
);
86 newRegion
= new wxShapeRegion
;
87 newRegion
->SetName("End");
88 newRegion
->SetSize(150, 50);
89 m_regions
.Append((wxObject
*)newRegion
);
91 for (int i
= 0; i
< 3; i
++)
92 m_labelObjects
[i
] = NULL
;
95 wxLineShape::~wxLineShape()
97 if (m_lineControlPoints
)
99 ClearPointList(*m_lineControlPoints
);
100 delete m_lineControlPoints
;
102 for (int i
= 0; i
< 3; i
++)
104 if (m_labelObjects
[i
])
106 m_labelObjects
[i
]->Select(FALSE
);
107 m_labelObjects
[i
]->RemoveFromCanvas(m_canvas
);
108 delete m_labelObjects
[i
];
109 m_labelObjects
[i
] = NULL
;
112 ClearArrowsAtPosition(-1);
115 void wxLineShape::MakeLineControlPoints(int n
)
117 if (m_lineControlPoints
)
119 ClearPointList(*m_lineControlPoints
);
120 delete m_lineControlPoints
;
122 m_lineControlPoints
= new wxList
;
125 for (i
= 0; i
< n
; i
++)
127 wxRealPoint
*point
= new wxRealPoint(-999, -999);
128 m_lineControlPoints
->Append((wxObject
*) point
);
132 wxNode
*wxLineShape::InsertLineControlPoint(wxDC
* dc
)
137 wxNode
*last
= m_lineControlPoints
->Last();
138 wxNode
*second_last
= last
->Previous();
139 wxRealPoint
*last_point
= (wxRealPoint
*)last
->Data();
140 wxRealPoint
*second_last_point
= (wxRealPoint
*)second_last
->Data();
142 // Choose a point half way between the last and penultimate points
143 float line_x
= ((last_point
->x
+ second_last_point
->x
)/2);
144 float line_y
= ((last_point
->y
+ second_last_point
->y
)/2);
146 wxRealPoint
*point
= new wxRealPoint(line_x
, line_y
);
147 wxNode
*node
= m_lineControlPoints
->Insert(last
, (wxObject
*) point
);
151 bool wxLineShape::DeleteLineControlPoint()
153 if (m_lineControlPoints
->Number() < 3)
156 wxNode
*last
= m_lineControlPoints
->Last();
157 wxNode
*second_last
= last
->Previous();
159 wxRealPoint
*second_last_point
= (wxRealPoint
*)second_last
->Data();
160 delete second_last_point
;
166 void wxLineShape::Initialise()
168 if (m_lineControlPoints
)
170 // Just move the first and last control points
171 wxNode
*first
= m_lineControlPoints
->First();
172 wxRealPoint
*first_point
= (wxRealPoint
*)first
->Data();
174 wxNode
*last
= m_lineControlPoints
->Last();
175 wxRealPoint
*last_point
= (wxRealPoint
*)last
->Data();
177 // If any of the line points are at -999, we must
178 // initialize them by placing them half way between the first
180 wxNode
*node
= first
->Next();
183 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
184 if (point
->x
== -999)
186 float x1
, y1
, x2
, y2
;
187 if (first_point
->x
< last_point
->x
)
188 { x1
= first_point
->x
; x2
= last_point
->x
; }
190 { x2
= first_point
->x
; x1
= last_point
->x
; }
192 if (first_point
->y
< last_point
->y
)
193 { y1
= first_point
->y
; y2
= last_point
->y
; }
195 { y2
= first_point
->y
; y1
= last_point
->y
; }
197 point
->x
= ((x2
- x1
)/2 + x1
);
198 point
->y
= ((y2
- y1
)/2 + y1
);
205 // Format a text string according to the region size, adding
206 // strings with positions to region text list
207 void wxLineShape::FormatText(wxDC
& dc
, const wxString
& s
, int i
)
212 if (m_regions
.Number() < 1)
214 wxNode
*node
= m_regions
.Nth(i
);
218 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
220 dc
.SetFont(region
->GetFont());
222 region
->GetSize(&w
, &h
);
223 // Initialize the size if zero
224 if (((w
== 0) || (h
== 0)) && (strlen(s
) > 0))
227 region
->SetSize(w
, h
);
230 wxList
*string_list
= ::FormatText(dc
, s
, (w
-5), (h
-5), region
->GetFormatMode());
231 node
= string_list
->First();
234 char *s
= (char *)node
->Data();
235 wxShapeTextLine
*line
= new wxShapeTextLine(0.0, 0.0, s
);
236 region
->GetFormattedText().Append((wxObject
*)line
);
238 node
= string_list
->First();
243 if (region
->GetFormatMode() & FORMAT_SIZE_TO_CONTENTS
)
245 GetCentredTextExtent(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, w
, h
, &actualW
, &actualH
);
246 if ((actualW
!= w
) || (actualH
!= h
))
249 GetLabelPosition(i
, &xx
, &yy
);
250 EraseRegion(dc
, region
, xx
, yy
);
251 if (m_labelObjects
[i
])
253 m_labelObjects
[i
]->Select(FALSE
);
254 m_labelObjects
[i
]->Erase(dc
);
255 m_labelObjects
[i
]->SetSize(actualW
, actualH
);
258 region
->SetSize(actualW
, actualH
);
260 if (m_labelObjects
[i
])
262 m_labelObjects
[i
]->Select(TRUE
, & dc
);
263 m_labelObjects
[i
]->Draw(dc
);
267 CentreText(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, actualW
, actualH
, region
->GetFormatMode());
271 void wxLineShape::DrawRegion(wxDC
& dc
, wxShapeRegion
*region
, float x
, float y
)
273 if (GetDisableLabel())
278 region
->GetSize(&w
, &h
);
280 // Get offset from x, y
281 region
->GetPosition(&xx
, &yy
);
286 // First, clear a rectangle for the text IF there is any
287 if (region
->GetFormattedText().Number() > 0)
289 dc
.SetPen(white_background_pen
);
290 dc
.SetBrush(white_background_brush
);
293 if (region
->GetFont()) dc
.SetFont(region
->GetFont());
295 dc
.DrawRectangle((float)(xp
- w
/2.0), (float)(yp
- h
/2.0), (float)w
, (float)h
);
297 if (m_pen
) dc
.SetPen(m_pen
);
298 dc
.SetTextForeground(* region
->GetActualColourObject());
301 dc
.SetTextBackground(white_background_brush
->GetColour());
304 DrawFormattedText(dc
, &(region
->GetFormattedText()), xp
, yp
, w
, h
, region
->GetFormatMode());
308 void wxLineShape::EraseRegion(wxDC
& dc
, wxShapeRegion
*region
, float x
, float y
)
310 if (GetDisableLabel())
315 region
->GetSize(&w
, &h
);
317 // Get offset from x, y
318 region
->GetPosition(&xx
, &yy
);
323 if (region
->GetFormattedText().Number() > 0)
325 dc
.SetPen(white_background_pen
);
326 dc
.SetBrush(white_background_brush
);
328 dc
.DrawRectangle((float)(xp
- w
/2.0), (float)(yp
- h
/2.0), (float)w
, (float)h
);
332 // Get the reference point for a label. Region x and y
333 // are offsets from this.
334 // position is 0, 1, 2
335 void wxLineShape::GetLabelPosition(int position
, float *x
, float *y
)
341 // Want to take the middle section for the label
342 int n
= m_lineControlPoints
->Number();
343 int half_way
= (int)(n
/2);
345 // Find middle of this line
346 wxNode
*node
= m_lineControlPoints
->Nth(half_way
- 1);
347 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
348 wxNode
*next_node
= node
->Next();
349 wxRealPoint
*next_point
= (wxRealPoint
*)next_node
->Data();
351 float dx
= (next_point
->x
- point
->x
);
352 float dy
= (next_point
->y
- point
->y
);
353 *x
= (float)(point
->x
+ dx
/2.0);
354 *y
= (float)(point
->y
+ dy
/2.0);
359 wxNode
*node
= m_lineControlPoints
->First();
360 *x
= ((wxRealPoint
*)node
->Data())->x
;
361 *y
= ((wxRealPoint
*)node
->Data())->y
;
366 wxNode
*node
= m_lineControlPoints
->Last();
367 *x
= ((wxRealPoint
*)node
->Data())->x
;
368 *y
= ((wxRealPoint
*)node
->Data())->y
;
377 * Find whether line is supposed to be vertical or horizontal and
381 void GraphicsStraightenLine(wxRealPoint
*point1
, wxRealPoint
*point2
)
383 float dx
= point2
->x
- point1
->x
;
384 float dy
= point2
->y
- point1
->y
;
388 else if (fabs(dy
/dx
) > 1.0)
390 point2
->x
= point1
->x
;
392 else point2
->y
= point1
->y
;
395 void wxLineShape::Straighten(wxDC
& dc
)
397 if (!m_lineControlPoints
|| m_lineControlPoints
->Number() < 3)
402 wxNode
*first_point_node
= m_lineControlPoints
->First();
403 wxNode
*last_point_node
= m_lineControlPoints
->Last();
404 wxNode
*second_last_point_node
= last_point_node
->Previous();
406 wxRealPoint
*last_point
= (wxRealPoint
*)last_point_node
->Data();
407 wxRealPoint
*second_last_point
= (wxRealPoint
*)second_last_point_node
->Data();
409 GraphicsStraightenLine(last_point
, second_last_point
);
411 wxNode
*node
= first_point_node
;
412 while (node
&& (node
!= second_last_point_node
))
414 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
415 wxRealPoint
*next_point
= (wxRealPoint
*)(node
->Next()->Data());
417 GraphicsStraightenLine(point
, next_point
);
425 void wxLineShape::Unlink()
428 m_to
->GetLines().DeleteObject(this);
430 m_from
->GetLines().DeleteObject(this);
435 void wxLineShape::SetEnds(float x1
, float y1
, float x2
, float y2
)
438 wxNode
*first_point_node
= m_lineControlPoints
->First();
439 wxNode
*last_point_node
= m_lineControlPoints
->Last();
440 wxRealPoint
*first_point
= (wxRealPoint
*)first_point_node
->Data();
441 wxRealPoint
*last_point
= (wxRealPoint
*)last_point_node
->Data();
448 m_xpos
= (float)((x1
+ x2
)/2.0);
449 m_ypos
= (float)((y1
+ y2
)/2.0);
452 // Get absolute positions of ends
453 void wxLineShape::GetEnds(float *x1
, float *y1
, float *x2
, float *y2
)
455 wxNode
*first_point_node
= m_lineControlPoints
->First();
456 wxNode
*last_point_node
= m_lineControlPoints
->Last();
457 wxRealPoint
*first_point
= (wxRealPoint
*)first_point_node
->Data();
458 wxRealPoint
*last_point
= (wxRealPoint
*)last_point_node
->Data();
460 *x1
= first_point
->x
; *y1
= first_point
->y
;
461 *x2
= last_point
->x
; *y2
= last_point
->y
;
464 void wxLineShape::SetAttachments(int from_attach
, int to_attach
)
466 m_attachmentFrom
= from_attach
;
467 m_attachmentTo
= to_attach
;
470 bool wxLineShape::HitTest(float x
, float y
, int *attachment
, float *distance
)
472 if (!m_lineControlPoints
)
475 // Look at label regions in case mouse is over a label
476 bool inLabelRegion
= FALSE
;
477 for (int i
= 0; i
< 3; i
++)
479 wxNode
*regionNode
= m_regions
.Nth(i
);
482 wxShapeRegion
*region
= (wxShapeRegion
*)regionNode
->Data();
483 if (region
->m_formattedText
.Number() > 0)
485 float xp
, yp
, cx
, cy
, cw
, ch
;
486 GetLabelPosition(i
, &xp
, &yp
);
487 // Offset region from default label position
488 region
->GetPosition(&cx
, &cy
);
489 region
->GetSize(&cw
, &ch
);
492 float rLeft
= (float)(cx
- (cw
/2.0));
493 float rTop
= (float)(cy
- (ch
/2.0));
494 float rRight
= (float)(cx
+ (cw
/2.0));
495 float rBottom
= (float)(cy
+ (ch
/2.0));
496 if (x
> rLeft
&& x
< rRight
&& y
> rTop
&& y
< rBottom
)
498 inLabelRegion
= TRUE
;
505 wxNode
*node
= m_lineControlPoints
->First();
507 while (node
&& node
->Next())
509 wxRealPoint
*point1
= (wxRealPoint
*)node
->Data();
510 wxRealPoint
*point2
= (wxRealPoint
*)node
->Next()->Data();
512 // Allow for inaccurate mousing or vert/horiz lines
514 float left
= wxMin(point1
->x
, point2
->x
) - extra
;
515 float right
= wxMax(point1
->x
, point2
->x
) + extra
;
517 float bottom
= wxMin(point1
->y
, point2
->y
) - extra
;
518 float top
= wxMax(point1
->y
, point2
->y
) + extra
;
520 if ((x
> left
&& x
< right
&& y
> bottom
&& y
< top
) || inLabelRegion
)
522 // Work out distance from centre of line
523 float centre_x
= (float)(left
+ (right
- left
)/2.0);
524 float centre_y
= (float)(bottom
+ (top
- bottom
)/2.0);
527 *distance
= (float)sqrt((centre_x
- x
)*(centre_x
- x
) + (centre_y
- y
)*(centre_y
- y
));
536 void wxLineShape::DrawArrows(wxDC
& dc
)
538 // Distance along line of each arrow: space them out evenly.
539 float startArrowPos
= 0.0;
540 float endArrowPos
= 0.0;
541 float middleArrowPos
= 0.0;
543 wxNode
*node
= m_arcArrows
.First();
546 wxArrowHead
*arrow
= (wxArrowHead
*)node
->Data();
547 switch (arrow
->GetArrowEnd())
549 case ARROW_POSITION_START
:
551 if ((arrow
->GetXOffset() != 0.0) && !m_ignoreArrowOffsets
)
552 // If specified, x offset is proportional to line length
553 DrawArrow(dc
, arrow
, arrow
->GetXOffset(), TRUE
);
556 DrawArrow(dc
, arrow
, startArrowPos
, FALSE
); // Absolute distance
557 startArrowPos
+= arrow
->GetSize() + arrow
->GetSpacing();
561 case ARROW_POSITION_END
:
563 if ((arrow
->GetXOffset() != 0.0) && !m_ignoreArrowOffsets
)
564 DrawArrow(dc
, arrow
, arrow
->GetXOffset(), TRUE
);
567 DrawArrow(dc
, arrow
, endArrowPos
, FALSE
);
568 endArrowPos
+= arrow
->GetSize() + arrow
->GetSpacing();
572 case ARROW_POSITION_MIDDLE
:
574 arrow
->SetXOffset(middleArrowPos
);
575 if ((arrow
->GetXOffset() != 0.0) && !m_ignoreArrowOffsets
)
576 DrawArrow(dc
, arrow
, arrow
->GetXOffset(), TRUE
);
579 DrawArrow(dc
, arrow
, middleArrowPos
, FALSE
);
580 middleArrowPos
+= arrow
->GetSize() + arrow
->GetSpacing();
589 void wxLineShape::DrawArrow(wxDC
& dc
, wxArrowHead
*arrow
, float xOffset
, bool proportionalOffset
)
591 wxNode
*first_line_node
= m_lineControlPoints
->First();
592 wxRealPoint
*first_line_point
= (wxRealPoint
*)first_line_node
->Data();
593 wxNode
*second_line_node
= first_line_node
->Next();
594 wxRealPoint
*second_line_point
= (wxRealPoint
*)second_line_node
->Data();
596 wxNode
*last_line_node
= m_lineControlPoints
->Last();
597 wxRealPoint
*last_line_point
= (wxRealPoint
*)last_line_node
->Data();
598 wxNode
*second_last_line_node
= last_line_node
->Previous();
599 wxRealPoint
*second_last_line_point
= (wxRealPoint
*)second_last_line_node
->Data();
601 // Position where we want to start drawing
602 float positionOnLineX
, positionOnLineY
;
604 // Position of start point of line, at the end of which we draw the arrow.
605 float startPositionX
, startPositionY
;
607 switch (arrow
->GetPosition())
609 case ARROW_POSITION_START
:
611 // If we're using a proportional offset, calculate just where this will
613 float realOffset
= xOffset
;
614 if (proportionalOffset
)
617 (float)sqrt((second_line_point
->x
- first_line_point
->x
)*(second_line_point
->x
- first_line_point
->x
) +
618 (second_line_point
->y
- first_line_point
->y
)*(second_line_point
->y
- first_line_point
->y
));
619 realOffset
= (float)(xOffset
* totalLength
);
621 GetPointOnLine(second_line_point
->x
, second_line_point
->y
,
622 first_line_point
->x
, first_line_point
->y
,
623 realOffset
, &positionOnLineX
, &positionOnLineY
);
624 startPositionX
= second_line_point
->x
;
625 startPositionY
= second_line_point
->y
;
628 case ARROW_POSITION_END
:
630 // If we're using a proportional offset, calculate just where this will
632 float realOffset
= xOffset
;
633 if (proportionalOffset
)
636 (float)sqrt((second_last_line_point
->x
- last_line_point
->x
)*(second_last_line_point
->x
- last_line_point
->x
) +
637 (second_last_line_point
->y
- last_line_point
->y
)*(second_last_line_point
->y
- last_line_point
->y
));
638 realOffset
= (float)(xOffset
* totalLength
);
640 GetPointOnLine(second_last_line_point
->x
, second_last_line_point
->y
,
641 last_line_point
->x
, last_line_point
->y
,
642 realOffset
, &positionOnLineX
, &positionOnLineY
);
643 startPositionX
= second_last_line_point
->x
;
644 startPositionY
= second_last_line_point
->y
;
647 case ARROW_POSITION_MIDDLE
:
649 // Choose a point half way between the last and penultimate points
650 float x
= ((last_line_point
->x
+ second_last_line_point
->x
)/2);
651 float y
= ((last_line_point
->y
+ second_last_line_point
->y
)/2);
653 // If we're using a proportional offset, calculate just where this will
655 float realOffset
= xOffset
;
656 if (proportionalOffset
)
659 (float)sqrt((second_last_line_point
->x
- x
)*(second_last_line_point
->x
- x
) +
660 (second_last_line_point
->y
- y
)*(second_last_line_point
->y
- y
));
661 realOffset
= (float)(xOffset
* totalLength
);
664 GetPointOnLine(second_last_line_point
->x
, second_last_line_point
->y
,
665 x
, y
, realOffset
, &positionOnLineX
, &positionOnLineY
);
666 startPositionX
= second_last_line_point
->x
;
667 startPositionY
= second_last_line_point
->y
;
673 * Add yOffset to arrow, if any
676 const float myPi
= (float) 3.14159265;
677 // The translation that the y offset may give
680 if ((arrow
->GetYOffset() != 0.0) && !m_ignoreArrowOffsets
)
686 (x1, y1)--------------(x3, y3)------------------(x2, y2)
687 x4 = x3 - d * sin(theta)
688 y4 = y3 + d * cos(theta)
690 Where theta = tan(-1) of (y3-y1)/(x3-x1)
692 float x1
= startPositionX
;
693 float y1
= startPositionY
;
694 float x3
= positionOnLineX
;
695 float y3
= positionOnLineY
;
696 float d
= -arrow
->GetYOffset(); // Negate so +offset is above line
700 theta
= (float)(myPi
/2.0);
702 theta
= (float)atan((y3
-y1
)/(x3
-x1
));
704 float x4
= (float)(x3
- (d
*sin(theta
)));
705 float y4
= (float)(y3
+ (d
*cos(theta
)));
707 deltaX
= x4
- positionOnLineX
;
708 deltaY
= y4
- positionOnLineY
;
711 switch (arrow
->_GetType())
715 float arrowLength
= arrow
->GetSize();
716 float arrowWidth
= (float)(arrowLength
/3.0);
718 float tip_x
, tip_y
, side1_x
, side1_y
, side2_x
, side2_y
;
719 get_arrow_points(startPositionX
+deltaX
, startPositionY
+deltaY
,
720 positionOnLineX
+deltaX
, positionOnLineY
+deltaY
,
721 arrowLength
, arrowWidth
, &tip_x
, &tip_y
,
722 &side1_x
, &side1_y
, &side2_x
, &side2_y
);
725 points
[0].x
= tip_x
; points
[0].y
= tip_y
;
726 points
[1].x
= side1_x
; points
[1].y
= side1_y
;
727 points
[2].x
= side2_x
; points
[2].y
= side2_y
;
728 points
[3].x
= tip_x
; points
[3].y
= tip_y
;
731 dc
.SetBrush(m_brush
);
732 dc
.DrawPolygon(4, points
);
735 case ARROW_HOLLOW_CIRCLE
:
736 case ARROW_FILLED_CIRCLE
:
738 // Find point on line of centre of circle, which is a radius away
739 // from the end position
740 float diameter
= (float)(arrow
->GetSize());
742 GetPointOnLine(startPositionX
+deltaX
, startPositionY
+deltaY
,
743 positionOnLineX
+deltaX
, positionOnLineY
+deltaY
,
744 (float)(diameter
/2.0),
747 // Convert ellipse centre to top-left coordinates
748 float x1
= (float)(x
- (diameter
/2.0));
749 float y1
= (float)(y
- (diameter
/2.0));
752 if (arrow
->_GetType() == ARROW_HOLLOW_CIRCLE
)
753 dc
.SetBrush(white_background_brush
);
755 dc
.SetBrush(m_brush
);
757 dc
.DrawEllipse(x1
, y1
, diameter
, diameter
);
760 case ARROW_SINGLE_OBLIQUE
:
766 if (arrow
->GetMetaFile())
768 // Find point on line of centre of object, which is a half-width away
769 // from the end position
772 * <-- start pos <-----><-- positionOnLineX
774 * --------------| x | <-- e.g. rectangular arrowhead
778 GetPointOnLine(startPositionX
, startPositionY
,
779 positionOnLineX
, positionOnLineY
,
780 (float)(arrow
->GetMetaFile()->m_width
/2.0),
783 // Calculate theta for rotating the metafile.
786 | o(x2, y2) 'o' represents the arrowhead.
791 |______________________
794 float x1
= startPositionX
;
795 float y1
= startPositionY
;
796 float x2
= positionOnLineX
;
797 float y2
= positionOnLineY
;
799 if ((x1
== x2
) && (y1
== y2
))
802 else if ((x1
== x2
) && (y1
> y2
))
803 theta
= (float)(3.0*myPi
/2.0);
805 else if ((x1
== x2
) && (y2
> y1
))
806 theta
= (float)(myPi
/2.0);
808 else if ((x2
> x1
) && (y2
>= y1
))
809 theta
= (float)atan((y2
- y1
)/(x2
- x1
));
812 theta
= (float)(myPi
+ atan((y2
- y1
)/(x2
- x1
)));
814 else if ((x2
> x1
) && (y2
< y1
))
815 theta
= (float)(2*myPi
+ atan((y2
- y1
)/(x2
- x1
)));
819 wxFatalError("Unknown arrowhead rotation case in lines.cc");
822 // Rotate about the centre of the object, then place
823 // the object on the line.
824 if (arrow
->GetMetaFile()->GetRotateable())
825 arrow
->GetMetaFile()->Rotate(0.0, 0.0, theta
);
829 // If erasing, just draw a rectangle.
830 float minX
, minY
, maxX
, maxY
;
831 arrow
->GetMetaFile()->GetBounds(&minX
, &minY
, &maxX
, &maxY
);
832 // Make erasing rectangle slightly bigger or you get droppings.
834 dc
.DrawRectangle((float)(deltaX
+ x
+ minX
- (extraPixels
/2.0)), (float)(deltaY
+ y
+ minY
- (extraPixels
/2.0)),
835 (float)(maxX
- minX
+ extraPixels
), (float)(maxY
- minY
+ extraPixels
));
838 arrow
->GetMetaFile()->Draw(dc
, x
+deltaX
, y
+deltaY
);
848 void wxLineShape::OnErase(wxDC
& dc
)
850 wxPen
*old_pen
= m_pen
;
851 wxBrush
*old_brush
= m_brush
;
852 SetPen(white_background_pen
);
853 SetBrush(white_background_brush
);
855 float bound_x
, bound_y
;
856 GetBoundingBoxMax(&bound_x
, &bound_y
);
857 if (m_font
) dc
.SetFont(m_font
);
859 // Undraw text regions
860 for (int i
= 0; i
< 3; i
++)
862 wxNode
*node
= m_regions
.Nth(i
);
866 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
867 GetLabelPosition(i
, &x
, &y
);
868 EraseRegion(dc
, region
, x
, y
);
873 dc
.SetPen(white_background_pen
);
874 dc
.SetBrush(white_background_brush
);
876 // Drawing over the line only seems to work if the line has a thickness
878 if (old_pen
&& (old_pen
->GetWidth() > 1))
880 dc
.DrawRectangle((float)(m_xpos
- (bound_x
/2.0) - 2.0), (float)(m_ypos
- (bound_y
/2.0) - 2.0),
881 (float)(bound_x
+4.0), (float)(bound_y
+4.0));
886 GetEventHandler()->OnDraw(dc
);
887 GetEventHandler()->OnEraseControlPoints(dc
);
891 if (old_pen
) SetPen(old_pen
);
892 if (old_brush
) SetBrush(old_brush
);
895 void wxLineShape::GetBoundingBoxMin(float *w
, float *h
)
902 wxNode
*node
= m_lineControlPoints
->First();
905 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
907 if (point
->x
< x1
) x1
= point
->x
;
908 if (point
->y
< y1
) y1
= point
->y
;
909 if (point
->x
> x2
) x2
= point
->x
;
910 if (point
->y
> y2
) y2
= point
->y
;
914 *w
= (float)(x2
- x1
);
915 *h
= (float)(y2
- y1
);
919 * For a node image of interest, finds the position of this arc
920 * amongst all the arcs which are attached to THIS SIDE of the node image,
921 * and the number of same.
923 void wxLineShape::FindNth(wxShape
*image
, int *nth
, int *no_arcs
, bool incoming
)
927 wxNode
*node
= image
->GetLines().First();
930 this_attachment
= m_attachmentTo
;
932 this_attachment
= m_attachmentFrom
;
934 // Find number of lines going into/out of this particular attachment point
937 wxLineShape
*line
= (wxLineShape
*)node
->Data();
939 if (line
->m_from
== image
)
941 // This is the nth line attached to 'image'
942 if ((line
== this) && !incoming
)
945 // Increment num count if this is the same side (attachment number)
946 if (line
->m_attachmentFrom
== this_attachment
)
950 if (line
->m_to
== image
)
952 // This is the nth line attached to 'image'
953 if ((line
== this) && incoming
)
956 // Increment num count if this is the same side (attachment number)
957 if (line
->m_attachmentTo
== this_attachment
)
967 void wxLineShape::OnDrawOutline(wxDC
& dc
, float x
, float y
, float w
, float h
)
969 wxPen
*old_pen
= m_pen
;
970 wxBrush
*old_brush
= m_brush
;
972 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
974 SetBrush( wxTRANSPARENT_BRUSH
);
978 dc.DrawSpline(m_lineControlPoints);
980 dc.DrawLines(m_lineControlPoints);
982 GetEventHandler()->OnDraw(dc
);
984 if (old_pen
) SetPen(old_pen
);
986 if (old_brush
) SetBrush(old_brush
);
990 bool wxLineShape::OnMovePre(wxDC
& dc
, float x
, float y
, float old_x
, float old_y
, bool display
)
992 float x_offset
= x
- old_x
;
993 float y_offset
= y
- old_y
;
995 if (m_lineControlPoints
&& !(x_offset
== 0.0 && y_offset
== 0.0))
997 wxNode
*node
= m_lineControlPoints
->First();
1000 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
1001 point
->x
+= x_offset
;
1002 point
->y
+= y_offset
;
1003 node
= node
->Next();
1008 // Move temporary label rectangles if necessary
1009 for (int i
= 0; i
< 3; i
++)
1011 if (m_labelObjects
[i
])
1013 m_labelObjects
[i
]->Erase(dc
);
1014 float xp
, yp
, xr
, yr
;
1015 GetLabelPosition(i
, &xp
, &yp
);
1016 wxNode
*node
= m_regions
.Nth(i
);
1019 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
1020 region
->GetPosition(&xr
, &yr
);
1027 m_labelObjects
[i
]->Move(dc
, xp
+xr
, yp
+yr
);
1033 void wxLineShape::OnMoveLink(wxDC
& dc
, bool moveControlPoints
)
1035 if (!m_from
|| !m_to
)
1038 if (m_lineControlPoints
->Number() > 2)
1041 // Do each end - nothing in the middle. User has to move other points
1042 // manually if necessary.
1044 float other_end_x
, other_end_y
;
1046 FindLineEndPoints(&end_x
, &end_y
, &other_end_x
, &other_end_y
);
1048 wxNode
*first
= m_lineControlPoints
->First();
1049 wxRealPoint
*first_point
= (wxRealPoint
*)first
->Data();
1050 wxNode
*last
= m_lineControlPoints
->Last();
1051 wxRealPoint
*last_point
= (wxRealPoint
*)last
->Data();
1053 /* This is redundant, surely? Done by SetEnds.
1054 first_point->x = end_x; first_point->y = end_y;
1055 last_point->x = other_end_x; last_point->y = other_end_y;
1058 float oldX
= m_xpos
;
1059 float oldY
= m_ypos
;
1061 SetEnds(end_x
, end_y
, other_end_x
, other_end_y
);
1063 // Do a second time, because one may depend on the other.
1064 FindLineEndPoints(&end_x
, &end_y
, &other_end_x
, &other_end_y
);
1065 SetEnds(end_x
, end_y
, other_end_x
, other_end_y
);
1067 // Try to move control points with the arc
1068 float x_offset
= m_xpos
- oldX
;
1069 float y_offset
= m_ypos
- oldY
;
1071 // if (moveControlPoints && m_lineControlPoints && !(x_offset == 0.0 && y_offset == 0.0))
1072 // Only move control points if it's a self link. And only works if attachment mode is ON.
1073 if ((m_from
== m_to
) && m_from
->GetAttachmentMode() && moveControlPoints
&& m_lineControlPoints
&& !(x_offset
== 0.0 && y_offset
== 0.0))
1075 wxNode
*node
= m_lineControlPoints
->First();
1078 if ((node
!= m_lineControlPoints
->First()) && (node
!= m_lineControlPoints
->Last()))
1080 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
1081 point
->x
+= x_offset
;
1082 point
->y
+= y_offset
;
1084 node
= node
->Next();
1088 Move(dc
, m_xpos
, m_ypos
);
1091 // Finds the x, y points at the two ends of the line.
1092 // This function can be used by e.g. line-routing routines to
1093 // get the actual points on the two node images where the lines will be drawn
1095 void wxLineShape::FindLineEndPoints(float *fromX
, float *fromY
, float *toX
, float *toY
)
1097 if (!m_from
|| !m_to
)
1100 // Do each end - nothing in the middle. User has to move other points
1101 // manually if necessary.
1103 float other_end_x
, other_end_y
;
1105 wxNode
*first
= m_lineControlPoints
->First();
1106 wxRealPoint
*first_point
= (wxRealPoint
*)first
->Data();
1107 wxNode
*last
= m_lineControlPoints
->Last();
1108 wxRealPoint
*last_point
= (wxRealPoint
*)last
->Data();
1110 wxNode
*second
= first
->Next();
1111 wxRealPoint
*second_point
= (wxRealPoint
*)second
->Data();
1113 wxNode
*second_last
= last
->Previous();
1114 wxRealPoint
*second_last_point
= (wxRealPoint
*)second_last
->Data();
1116 if (m_lineControlPoints
->Number() > 2)
1118 if (m_from
->GetAttachmentMode())
1121 FindNth(m_from
, &nth
, &no_arcs
, FALSE
); // Not incoming
1122 m_from
->GetAttachmentPosition(m_attachmentFrom
, &end_x
, &end_y
, nth
, no_arcs
, this);
1125 (void) m_from
->GetPerimeterPoint(m_from
->GetX(), m_from
->GetY(),
1126 (float)second_point
->x
, (float)second_point
->y
,
1129 if (m_to
->GetAttachmentMode())
1132 FindNth(m_to
, &nth
, &no_arcs
, TRUE
); // Incoming
1133 m_to
->GetAttachmentPosition(m_attachmentTo
, &other_end_x
, &other_end_y
, nth
, no_arcs
, this);
1136 (void) m_to
->GetPerimeterPoint(m_to
->GetX(), m_to
->GetY(),
1137 (float)second_last_point
->x
, (float)second_last_point
->y
,
1138 &other_end_x
, &other_end_y
);
1142 float fromX
= m_from
->GetX();
1143 float fromY
= m_from
->GetY();
1144 float toX
= m_to
->GetX();
1145 float toY
= m_to
->GetY();
1147 if (m_from
->GetAttachmentMode())
1150 FindNth(m_from
, &nth
, &no_arcs
, FALSE
);
1151 m_from
->GetAttachmentPosition(m_attachmentFrom
, &end_x
, &end_y
, nth
, no_arcs
, this);
1156 if (m_to
->GetAttachmentMode())
1159 FindNth(m_to
, &nth
, &no_arcs
, TRUE
);
1160 m_to
->GetAttachmentPosition(m_attachmentTo
, &other_end_x
, &other_end_y
, nth
, no_arcs
, this);
1165 if (!m_from
->GetAttachmentMode())
1166 (void) m_from
->GetPerimeterPoint(m_from
->GetX(), m_from
->GetY(),
1170 if (!m_to
->GetAttachmentMode())
1171 (void) m_to
->GetPerimeterPoint(m_to
->GetX(), m_to
->GetY(),
1173 &other_end_x
, &other_end_y
);
1181 void wxLineShape::OnDraw(wxDC
& dc
)
1183 if (m_lineControlPoints
)
1188 dc
.SetBrush(m_brush
);
1190 int n
= m_lineControlPoints
->Number();
1191 wxPoint
*points
= new wxPoint
[n
];
1193 for (i
= 0; i
< n
; i
++)
1195 wxRealPoint
* point
= (wxRealPoint
*) m_lineControlPoints
->Nth(i
)->Data();
1196 points
[i
].x
= (int) point
->x
;
1197 points
[i
].y
= (int) point
->y
;
1201 dc
.DrawSpline(n
, points
);
1203 dc
.DrawLines(n
, points
);
1207 // Problem with pen - if not a solid pen, does strange things
1208 // to the arrowhead. So make (get) a new pen that's solid.
1209 if (m_pen
&& (m_pen
->GetStyle() != wxSOLID
))
1212 wxThePenList
->FindOrCreatePen(m_pen
->GetColour(), 1, wxSOLID
);
1214 dc
.SetPen(solid_pen
);
1220 void wxLineShape::OnDrawControlPoints(wxDC
& dc
)
1225 // Draw temporary label rectangles if necessary
1226 for (int i
= 0; i
< 3; i
++)
1228 if (m_labelObjects
[i
])
1229 m_labelObjects
[i
]->Draw(dc
);
1231 wxShape::OnDrawControlPoints(dc
);
1234 void wxLineShape::OnEraseControlPoints(wxDC
& dc
)
1236 // Erase temporary label rectangles if necessary
1237 for (int i
= 0; i
< 3; i
++)
1239 if (m_labelObjects
[i
])
1240 m_labelObjects
[i
]->Erase(dc
);
1242 wxShape::OnEraseControlPoints(dc
);
1245 void wxLineShape::OnDragLeft(bool draw
, float x
, float y
, int keys
, int attachment
)
1249 void wxLineShape::OnBeginDragLeft(float x
, float y
, int keys
, int attachment
)
1253 void wxLineShape::OnEndDragLeft(float x
, float y
, int keys
, int attachment
)
1258 void wxLineShape::SetArrowSize(float length, float width)
1260 arrow_length = length;
1261 arrow_width = width;
1264 void wxLineShape::SetStartArrow(int style)
1266 start_style = style;
1269 void wxLineShape::SetMiddleArrow(int style)
1271 middle_style = style;
1274 void wxLineShape::SetEndArrow(int style)
1280 void wxLineShape::OnDrawContents(wxDC
& dc
)
1282 if (GetDisableLabel())
1285 for (int i
= 0; i
< 3; i
++)
1287 wxNode
*node
= m_regions
.Nth(i
);
1290 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
1292 GetLabelPosition(i
, &x
, &y
);
1293 DrawRegion(dc
, region
, x
, y
);
1300 char *wxLineShape::GetFunctor()
1306 void wxLineShape::SetTo(wxShape
*object
)
1311 void wxLineShape::SetFrom(wxShape
*object
)
1316 void wxLineShape::MakeControlPoints()
1318 if (m_canvas
&& m_lineControlPoints
)
1320 wxNode
*first
= m_lineControlPoints
->First();
1321 wxNode
*last
= m_lineControlPoints
->Last();
1322 wxRealPoint
*first_point
= (wxRealPoint
*)first
->Data();
1323 wxRealPoint
*last_point
= (wxRealPoint
*)last
->Data();
1325 wxLineControlPoint
*control
= new wxLineControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
,
1326 first_point
->x
, first_point
->y
,
1327 CONTROL_POINT_ENDPOINT_FROM
);
1328 control
->m_point
= first_point
;
1329 m_canvas
->AddShape(control
);
1330 m_controlPoints
.Append(control
);
1333 wxNode
*node
= first
->Next();
1334 while (node
!= last
)
1336 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
1338 control
= new wxLineControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
,
1340 CONTROL_POINT_LINE
);
1341 control
->m_point
= point
;
1343 m_canvas
->AddShape(control
);
1344 m_controlPoints
.Append(control
);
1346 node
= node
->Next();
1348 control
= new wxLineControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
,
1349 last_point
->x
, last_point
->y
,
1350 CONTROL_POINT_ENDPOINT_TO
);
1351 control
->m_point
= last_point
;
1352 m_canvas
->AddShape(control
);
1353 m_controlPoints
.Append(control
);
1359 void wxLineShape::ResetControlPoints()
1361 if (m_canvas
&& m_lineControlPoints
&& m_controlPoints
.Number() > 0)
1363 wxNode
*node
= m_controlPoints
.First();
1364 wxNode
*control_node
= m_lineControlPoints
->First();
1365 while (node
&& control_node
)
1367 wxRealPoint
*point
= (wxRealPoint
*)control_node
->Data();
1368 wxLineControlPoint
*control
= (wxLineControlPoint
*)node
->Data();
1369 control
->SetX(point
->x
);
1370 control
->SetY(point
->y
);
1372 node
= node
->Next();
1373 control_node
= control_node
->Next();
1379 void wxLineShape::WritePrologAttributes(wxExpr
*clause
)
1381 wxShape::WritePrologAttributes(clause
);
1384 clause
->AddAttributeValue("from", m_from
->GetId());
1386 clause
->AddAttributeValue("to", m_to
->GetId());
1388 if (m_attachmentTo
!= 0)
1389 clause
->AddAttributeValue("attachment_to", (long)m_attachmentTo
);
1390 if (m_attachmentFrom
!= 0)
1391 clause
->AddAttributeValue("attachment_from", (long)m_attachmentFrom
);
1393 if (m_alignmentStart
!= 0)
1394 clause
->AddAttributeValue("align_start", (long)m_alignmentStart
);
1395 if (m_alignmentEnd
!= 0)
1396 clause
->AddAttributeValue("align_end", (long)m_alignmentEnd
);
1398 clause
->AddAttributeValue("is_spline", (long)m_isSpline
);
1399 if (m_maintainStraightLines
)
1400 clause
->AddAttributeValue("keep_lines_straight", (long)m_maintainStraightLines
);
1402 // Make a list of lists for the (sp)line controls
1403 wxExpr
*list
= new wxExpr(PrologList
);
1404 wxNode
*node
= m_lineControlPoints
->First();
1407 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
1408 wxExpr
*point_list
= new wxExpr(PrologList
);
1409 wxExpr
*x_expr
= new wxExpr((float) point
->x
);
1410 wxExpr
*y_expr
= new wxExpr((float) point
->y
);
1411 point_list
->Append(x_expr
);
1412 point_list
->Append(y_expr
);
1413 list
->Append(point_list
);
1415 node
= node
->Next();
1417 clause
->AddAttributeValue("controls", list
);
1419 // Write arc arrows in new OGL format, if there are any.
1420 // This is a list of lists. Each sublist comprises:
1421 // (arrowType arrowEnd xOffset arrowSize)
1422 if (m_arcArrows
.Number() > 0)
1424 wxExpr
*arrow_list
= new wxExpr(PrologList
);
1425 node
= m_arcArrows
.First();
1428 wxArrowHead
*head
= (wxArrowHead
*)node
->Data();
1429 wxExpr
*head_list
= new wxExpr(PrologList
);
1430 head_list
->Append(new wxExpr((long)head
->_GetType()));
1431 head_list
->Append(new wxExpr((long)head
->GetArrowEnd()));
1432 head_list
->Append(new wxExpr(head
->GetXOffset()));
1433 head_list
->Append(new wxExpr(head
->GetArrowSize()));
1434 head_list
->Append(new wxExpr(PrologString
, (head
->GetName() ? head
->GetName() : "")));
1435 head_list
->Append(new wxExpr(head
->GetId()));
1437 // New members of wxArrowHead
1438 head_list
->Append(new wxExpr(head
->GetYOffset()));
1439 head_list
->Append(new wxExpr(head
->GetSpacing()));
1441 arrow_list
->Append(head_list
);
1443 node
= node
->Next();
1445 clause
->AddAttributeValue("arrows", arrow_list
);
1449 void wxLineShape::ReadPrologAttributes(wxExpr
*clause
)
1451 wxShape::ReadPrologAttributes(clause
);
1453 int iVal
= (int) m_isSpline
;
1454 clause
->AssignAttributeValue("is_spline", &iVal
);
1455 m_isSpline
= (iVal
!= 0);
1457 iVal
= (int) m_maintainStraightLines
;
1458 clause
->AssignAttributeValue("keep_lines_straight", &iVal
);
1459 m_maintainStraightLines
= (iVal
!= 0);
1461 clause
->AssignAttributeValue("align_start", &m_alignmentStart
);
1462 clause
->AssignAttributeValue("align_end", &m_alignmentEnd
);
1464 // Compatibility: check for no regions.
1465 if (m_regions
.Number() == 0)
1467 wxShapeRegion
*newRegion
= new wxShapeRegion
;
1468 newRegion
->SetName("Middle");
1469 newRegion
->SetSize(150, 50);
1470 m_regions
.Append((wxObject
*)newRegion
);
1471 if (m_text
.Number() > 0)
1473 newRegion
->ClearText();
1474 wxNode
*node
= m_text
.First();
1477 wxShapeTextLine
*textLine
= (wxShapeTextLine
*)node
->Data();
1478 wxNode
*next
= node
->Next();
1479 newRegion
->GetFormattedText().Append((wxObject
*)textLine
);
1485 newRegion
= new wxShapeRegion
;
1486 newRegion
->SetName("Start");
1487 newRegion
->SetSize(150, 50);
1488 m_regions
.Append((wxObject
*)newRegion
);
1490 newRegion
= new wxShapeRegion
;
1491 newRegion
->SetName("End");
1492 newRegion
->SetSize(150, 50);
1493 m_regions
.Append((wxObject
*)newRegion
);
1497 m_attachmentFrom
= 0;
1499 clause
->AssignAttributeValue("attachment_to", &m_attachmentTo
);
1500 clause
->AssignAttributeValue("attachmen_from", &m_attachmentFrom
);
1502 wxExpr
*line_list
= NULL
;
1504 // When image is created, there are default control points. Override
1505 // them if there are some in the file.
1506 clause
->AssignAttributeValue("controls", &line_list
);
1510 // Read a list of lists for the spline controls
1511 if (m_lineControlPoints
)
1513 ClearPointList(*m_lineControlPoints
);
1516 m_lineControlPoints
= new wxList
;
1518 wxExpr
*node
= line_list
->value
.first
;
1522 wxExpr
*xexpr
= node
->value
.first
;
1523 float x
= xexpr
->RealValue();
1525 wxExpr
*yexpr
= xexpr
->next
;
1526 float y
= yexpr
->RealValue();
1528 wxRealPoint
*point
= new wxRealPoint(x
, y
);
1529 m_lineControlPoints
->Append((wxObject
*) point
);
1535 // Read arrow list, for new OGL code
1536 wxExpr
*arrow_list
= NULL
;
1538 clause
->AssignAttributeValue("arrows", &arrow_list
);
1541 wxExpr
*node
= arrow_list
->value
.first
;
1545 WXTYPE arrowType
= ARROW_ARROW
;
1547 float xOffset
= 0.0;
1548 float arrowSize
= 0.0;
1549 wxString
arrowName("");
1552 wxExpr
*type_expr
= node
->Nth(0);
1553 wxExpr
*end_expr
= node
->Nth(1);
1554 wxExpr
*dist_expr
= node
->Nth(2);
1555 wxExpr
*size_expr
= node
->Nth(3);
1556 wxExpr
*name_expr
= node
->Nth(4);
1557 wxExpr
*id_expr
= node
->Nth(5);
1559 // New members of wxArrowHead
1560 wxExpr
*yOffsetExpr
= node
->Nth(6);
1561 wxExpr
*spacingExpr
= node
->Nth(7);
1564 arrowType
= (int)type_expr
->IntegerValue();
1566 arrowEnd
= (int)end_expr
->IntegerValue();
1568 xOffset
= dist_expr
->RealValue();
1570 arrowSize
= size_expr
->RealValue();
1572 arrowName
= name_expr
->StringValue();
1574 arrowId
= id_expr
->IntegerValue();
1579 RegisterId(arrowId
);
1581 wxArrowHead
*arrowHead
= AddArrow(arrowType
, arrowEnd
, arrowSize
, xOffset
, (char*) (const char*) arrowName
, NULL
, arrowId
);
1583 arrowHead
->SetYOffset(yOffsetExpr
->RealValue());
1585 arrowHead
->SetSpacing(spacingExpr
->RealValue());
1593 void wxLineShape::Copy(wxShape
& copy
)
1595 wxShape::Copy(copy
);
1597 wxASSERT( copy
.IsKindOf(CLASSINFO(wxLineShape
)) );
1599 wxLineShape
& lineCopy
= (wxLineShape
&) copy
;
1601 lineCopy
.m_isSpline
= m_isSpline
;
1602 lineCopy
.m_alignmentStart
= m_alignmentStart
;
1603 lineCopy
.m_alignmentEnd
= m_alignmentEnd
;
1604 lineCopy
.m_maintainStraightLines
= m_maintainStraightLines
;
1605 lineCopy
.m_lineOrientations
.Clear();
1606 wxNode
*node
= m_lineOrientations
.First();
1609 lineCopy
.m_lineOrientations
.Append(node
->Data());
1610 node
= node
->Next();
1613 if (lineCopy
.m_lineControlPoints
)
1615 ClearPointList(*lineCopy
.m_lineControlPoints
);
1616 delete lineCopy
.m_lineControlPoints
;
1619 lineCopy
.m_lineControlPoints
= new wxList
;
1621 node
= m_lineControlPoints
->First();
1624 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
1625 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
1626 lineCopy
.m_lineControlPoints
->Append((wxObject
*) new_point
);
1627 node
= node
->Next();
1631 lineCopy.start_style = start_style;
1632 lineCopy.end_style = end_style;
1633 lineCopy.middle_style = middle_style;
1635 lineCopy.arrow_length = arrow_length;
1636 lineCopy.arrow_width = arrow_width;
1639 // Copy new OGL stuff
1640 lineCopy
.ClearArrowsAtPosition(-1);
1641 node
= m_arcArrows
.First();
1644 wxArrowHead
*arrow
= (wxArrowHead
*)node
->Data();
1645 lineCopy
.m_arcArrows
.Append(new wxArrowHead(*arrow
));
1646 node
= node
->Next();
1650 // Override select, to create/delete temporary label-moving objects
1651 void wxLineShape::Select(bool select
, wxDC
* dc
)
1653 wxShape::Select(select
);
1656 for (int i
= 0; i
< 3; i
++)
1658 wxNode
*node
= m_regions
.Nth(i
);
1661 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
1662 if (region
->m_formattedText
.Number() > 0)
1664 float w
, h
, x
, y
, xx
, yy
;
1665 region
->GetSize(&w
, &h
);
1666 region
->GetPosition(&x
, &y
);
1667 GetLabelPosition(i
, &xx
, &yy
);
1668 if (m_labelObjects
[i
])
1670 m_labelObjects
[i
]->Select(FALSE
);
1671 m_labelObjects
[i
]->RemoveFromCanvas(m_canvas
);
1672 delete m_labelObjects
[i
];
1674 m_labelObjects
[i
] = new wxLabelShape(this, region
, w
, h
);
1675 m_labelObjects
[i
]->AddToCanvas(m_canvas
);
1676 m_labelObjects
[i
]->Show(TRUE
);
1678 m_labelObjects
[i
]->Move(*dc
, (float)(x
+ xx
), (float)(y
+ yy
));
1679 m_labelObjects
[i
]->Select(TRUE
);
1686 for (int i
= 0; i
< 3; i
++)
1688 if (m_labelObjects
[i
])
1690 m_labelObjects
[i
]->Select(FALSE
, dc
);
1691 m_labelObjects
[i
]->RemoveFromCanvas(m_canvas
);
1692 delete m_labelObjects
[i
];
1693 m_labelObjects
[i
] = NULL
;
1700 * Line control point
1704 IMPLEMENT_DYNAMIC_CLASS(wxLineControlPoint
, wxControlPoint
)
1706 wxLineControlPoint::wxLineControlPoint(wxShapeCanvas
*theCanvas
, wxShape
*object
, float size
, float x
, float y
, int the_type
):
1707 wxControlPoint(theCanvas
, object
, size
, x
, y
, the_type
)
1714 wxLineControlPoint::~wxLineControlPoint()
1718 void wxLineControlPoint::OnDraw(wxDC
& dc
)
1720 wxRectangleShape::OnDraw(dc
);
1723 // Implement movement of Line point
1724 void wxLineControlPoint::OnDragLeft(bool draw
, float x
, float y
, int keys
, int attachment
)
1726 m_shape
->GetEventHandler()->OnSizingDragLeft(this, draw
, x
, y
, keys
, attachment
);
1729 void wxLineControlPoint::OnBeginDragLeft(float x
, float y
, int keys
, int attachment
)
1731 m_shape
->GetEventHandler()->OnSizingBeginDragLeft(this, x
, y
, keys
, attachment
);
1734 void wxLineControlPoint::OnEndDragLeft(float x
, float y
, int keys
, int attachment
)
1736 m_shape
->GetEventHandler()->OnSizingEndDragLeft(this, x
, y
, keys
, attachment
);
1739 // Control points ('handles') redirect control to the actual shape, to make it easier
1740 // to override sizing behaviour.
1741 void wxLineShape::OnSizingDragLeft(wxControlPoint
* pt
, bool draw
, float x
, float y
, int keys
, int attachment
)
1743 wxLineControlPoint
* lpt
= (wxLineControlPoint
*) pt
;
1745 wxClientDC
dc(GetCanvas());
1746 GetCanvas()->PrepareDC(dc
);
1748 dc
.SetLogicalFunction(wxXOR
);
1750 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1751 dc
.SetPen(dottedPen
);
1752 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1754 if (lpt
->m_type
== CONTROL_POINT_LINE
)
1756 m_canvas
->Snap(&x
, &y
);
1758 lpt
->SetX(x
); lpt
->SetY(y
);
1759 lpt
->m_point
->x
= x
; lpt
->m_point
->y
= y
;
1761 wxLineShape
*lineShape
= (wxLineShape
*)this;
1763 wxPen
*old_pen
= lineShape
->GetPen();
1764 wxBrush
*old_brush
= lineShape
->GetBrush();
1766 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1767 lineShape
->SetPen(& dottedPen
);
1768 lineShape
->SetBrush(wxTRANSPARENT_BRUSH
);
1770 lineShape
->GetEventHandler()->OnMoveLink(dc
, FALSE
);
1772 lineShape
->SetPen(old_pen
);
1773 lineShape
->SetBrush(old_brush
);
1776 if (lpt
->m_type
== CONTROL_POINT_ENDPOINT_FROM
|| lpt
->m_type
== CONTROL_POINT_ENDPOINT_TO
)
1778 lpt
->SetX(x
); lpt
->SetY(y
);
1783 void wxLineShape::OnSizingBeginDragLeft(wxControlPoint
* pt
, float x
, float y
, int keys
, int attachment
)
1785 wxLineControlPoint
* lpt
= (wxLineControlPoint
*) pt
;
1787 wxClientDC
dc(GetCanvas());
1788 GetCanvas()->PrepareDC(dc
);
1790 wxLineShape
*lineShape
= (wxLineShape
*)this;
1791 if (lpt
->m_type
== CONTROL_POINT_LINE
)
1793 m_canvas
->Snap(&x
, &y
);
1797 // Redraw start and end objects because we've left holes
1798 // when erasing the line
1799 lineShape
->GetFrom()->OnDraw(dc
);
1800 lineShape
->GetFrom()->OnDrawContents(dc
);
1801 lineShape
->GetTo()->OnDraw(dc
);
1802 lineShape
->GetTo()->OnDrawContents(dc
);
1804 this->SetDisableLabel(TRUE
);
1805 dc
.SetLogicalFunction(wxXOR
);
1807 lpt
->m_xpos
= x
; lpt
->m_ypos
= y
;
1808 lpt
->m_point
->x
= x
; lpt
->m_point
->y
= y
;
1810 wxPen
*old_pen
= lineShape
->GetPen();
1811 wxBrush
*old_brush
= lineShape
->GetBrush();
1813 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1814 lineShape
->SetPen(& dottedPen
);
1815 lineShape
->SetBrush(wxTRANSPARENT_BRUSH
);
1817 lineShape
->GetEventHandler()->OnMoveLink(dc
, FALSE
);
1819 lineShape
->SetPen(old_pen
);
1820 lineShape
->SetBrush(old_brush
);
1823 if (lpt
->m_type
== CONTROL_POINT_ENDPOINT_FROM
|| lpt
->m_type
== CONTROL_POINT_ENDPOINT_TO
)
1826 lineShape
->OnDraw(dc
);
1827 if (lpt
->m_type
== CONTROL_POINT_ENDPOINT_FROM
)
1829 lineShape
->GetFrom()->OnDraw(dc
);
1830 lineShape
->GetFrom()->OnDrawContents(dc
);
1834 lineShape
->GetTo()->OnDraw(dc
);
1835 lineShape
->GetTo()->OnDrawContents(dc
);
1837 m_canvas
->SetCursor(GraphicsBullseyeCursor
);
1838 lpt
->m_oldCursor
= wxSTANDARD_CURSOR
;
1842 void wxLineShape::OnSizingEndDragLeft(wxControlPoint
* pt
, float x
, float y
, int keys
, int attachment
)
1844 wxLineControlPoint
* lpt
= (wxLineControlPoint
*) pt
;
1846 wxClientDC
dc(GetCanvas());
1847 GetCanvas()->PrepareDC(dc
);
1849 this->SetDisableLabel(FALSE
);
1850 wxLineShape
*lineShape
= (wxLineShape
*)this;
1852 if (lpt
->m_type
== CONTROL_POINT_LINE
)
1854 m_canvas
->Snap(&x
, &y
);
1856 dc
.SetLogicalFunction(wxCOPY
);
1857 lpt
->m_xpos
= x
; lpt
->m_ypos
= y
;
1858 lpt
->m_point
->x
= x
; lpt
->m_point
->y
= y
;
1860 lineShape
->GetEventHandler()->OnMoveLink(dc
);
1862 if (lpt
->m_type
== CONTROL_POINT_ENDPOINT_FROM
)
1864 if (lpt
->m_oldCursor
)
1865 m_canvas
->SetCursor(lpt
->m_oldCursor
);
1868 lpt
->m_xpos
= x
; lpt
->m_ypos
= y
;
1870 if (lineShape
->GetFrom())
1872 lineShape
->GetFrom()->MoveLineToNewAttachment(dc
, lineShape
, x
, y
);
1873 lineShape
->GetFrom()->MoveLinks(dc
);
1876 if (lpt
->m_type
== CONTROL_POINT_ENDPOINT_TO
)
1878 if (lpt
->m_oldCursor
)
1879 m_canvas
->SetCursor(lpt
->m_oldCursor
);
1881 lpt
->m_xpos
= x
; lpt
->m_ypos
= y
;
1883 if (lineShape
->GetTo())
1885 lineShape
->GetTo()->MoveLineToNewAttachment(dc
, lineShape
, x
, y
);
1886 lineShape
->GetTo()->MoveLinks(dc
);
1890 for (i
= 0; i
< lineShape
->GetLineControlPoints()->Number(); i
++)
1891 if (((wxRealPoint
*)(lineShape
->GetLineControlPoints()->Nth(i
)->Data())) == lpt
->m_point
)
1894 // N.B. in OnMoveControlPoint, an event handler in Hardy could have deselected
1895 // the line and therefore deleted 'this'. -> GPF, intermittently.
1896 // So assume at this point that we've been blown away.
1897 wxLineShape
*lineObj
= lineShape
;
1898 wxShapeCanvas
*objCanvas
= m_canvas
;
1900 lineObj
->OnMoveControlPoint(i
+1, x
, y
);
1902 if (!objCanvas
->GetQuickEditMode()) objCanvas
->Redraw(dc
);
1905 // Implement movement of endpoint to a new attachment
1906 void wxLineControlPoint::OnDragRight(bool draw
, float x
, float y
, int keys
, int attachment
)
1908 if (m_type
== CONTROL_POINT_ENDPOINT_FROM
|| m_type
== CONTROL_POINT_ENDPOINT_TO
)
1910 m_xpos
= x
; m_ypos
= y
;
1914 void wxLineControlPoint::OnBeginDragRight(float x
, float y
, int keys
, int attachment
)
1916 wxClientDC
dc(GetCanvas());
1917 GetCanvas()->PrepareDC(dc
);
1919 wxLineShape
*lineShape
= (wxLineShape
*)m_shape
;
1920 if (m_type
== CONTROL_POINT_ENDPOINT_FROM
|| m_type
== CONTROL_POINT_ENDPOINT_TO
)
1923 lineShape
->GetEventHandler()->OnDraw(dc
);
1924 if (m_type
== CONTROL_POINT_ENDPOINT_FROM
)
1926 lineShape
->GetFrom()->GetEventHandler()->OnDraw(dc
);
1927 lineShape
->GetFrom()->GetEventHandler()->OnDrawContents(dc
);
1931 lineShape
->GetTo()->GetEventHandler()->OnDraw(dc
);
1932 lineShape
->GetTo()->GetEventHandler()->OnDrawContents(dc
);
1934 m_canvas
->SetCursor(GraphicsBullseyeCursor
);
1935 m_oldCursor
= wxSTANDARD_CURSOR
;
1939 void wxLineControlPoint::OnEndDragRight(float x
, float y
, int keys
, int attachment
)
1941 wxClientDC
dc(GetCanvas());
1942 GetCanvas()->PrepareDC(dc
);
1944 wxLineShape
*lineShape
= (wxLineShape
*)m_shape
;
1945 if (m_type
== CONTROL_POINT_ENDPOINT_FROM
)
1948 m_canvas
->SetCursor(m_oldCursor
);
1950 m_xpos
= x
; m_ypos
= y
;
1952 if (lineShape
->GetFrom())
1954 lineShape
->GetFrom()->EraseLinks(dc
);
1959 if (lineShape
->GetFrom()->HitTest(x
, y
, &new_attachment
, &distance
))
1960 lineShape
->SetAttachments(new_attachment
, lineShape
->GetAttachmentTo());
1962 lineShape
->GetFrom()->MoveLinks(dc
);
1965 if (m_type
== CONTROL_POINT_ENDPOINT_TO
)
1968 m_canvas
->SetCursor(m_oldCursor
);
1971 m_xpos
= x
; m_ypos
= y
;
1973 if (lineShape
->GetTo())
1975 lineShape
->GetTo()->EraseLinks(dc
);
1979 if (lineShape
->GetTo()->HitTest(x
, y
, &new_attachment
, &distance
))
1980 lineShape
->SetAttachments(lineShape
->GetAttachmentFrom(), new_attachment
);
1982 lineShape
->GetTo()->MoveLinks(dc
);
1986 for (i
= 0; i
< lineShape
->GetLineControlPoints()->Number(); i
++)
1987 if (((wxRealPoint
*)(lineShape
->GetLineControlPoints()->Nth(i
)->Data())) == m_point
)
1989 lineShape
->OnMoveControlPoint(i
+1, x
, y
);
1990 if (!m_canvas
->GetQuickEditMode()) m_canvas
->Redraw(dc
);
1994 * Get the point on the given line (x1, y1) (x2, y2)
1995 * distance 'length' along from the end,
1996 * returned values in x and y
1999 void GetPointOnLine(float x1
, float y1
, float x2
, float y2
,
2000 float length
, float *x
, float *y
)
2002 float l
= (float)sqrt((x2
- x1
)*(x2
- x1
) + (y2
- y1
)*(y2
- y1
));
2007 float i_bar
= (x2
- x1
)/l
;
2008 float j_bar
= (y2
- y1
)/l
;
2010 *x
= (- length
*i_bar
) + x2
;
2011 *y
= (- length
*j_bar
) + y2
;
2014 wxArrowHead
*wxLineShape::AddArrow(WXTYPE type
, int end
, float size
, float xOffset
,
2015 const wxString
& name
, wxPseudoMetaFile
*mf
, long arrowId
)
2017 wxArrowHead
*arrow
= new wxArrowHead(type
, end
, size
, xOffset
, name
, mf
, arrowId
);
2018 m_arcArrows
.Append(arrow
);
2023 * Add arrowhead at a particular position in the arrowhead list.
2025 bool wxLineShape::AddArrowOrdered(wxArrowHead
*arrow
, wxList
& referenceList
, int end
)
2027 wxNode
*refNode
= referenceList
.First();
2028 wxNode
*currNode
= m_arcArrows
.First();
2029 wxString
targetName(arrow
->GetName());
2030 if (!refNode
) return FALSE
;
2032 // First check whether we need to insert in front of list,
2033 // because this arrowhead is the first in the reference
2034 // list and should therefore be first in the current list.
2035 wxArrowHead
*refArrow
= (wxArrowHead
*)refNode
->Data();
2036 if (refArrow
->GetName() == targetName
)
2038 m_arcArrows
.Insert(arrow
);
2042 while (refNode
&& currNode
)
2044 wxArrowHead
*currArrow
= (wxArrowHead
*)currNode
->Data();
2045 refArrow
= (wxArrowHead
*)refNode
->Data();
2047 // Matching: advance current arrow pointer
2048 if ((currArrow
->GetArrowEnd() == end
) &&
2049 (currArrow
->GetName() == refArrow
->GetName()))
2051 currNode
= currNode
->Next(); // Could be NULL now
2053 currArrow
= (wxArrowHead
*)currNode
->Data();
2056 // Check if we're at the correct position in the
2058 if (targetName
== refArrow
->GetName())
2061 m_arcArrows
.Insert(currNode
, arrow
);
2063 m_arcArrows
.Append(arrow
);
2066 refNode
= refNode
->Next();
2068 m_arcArrows
.Append(arrow
);
2072 void wxLineShape::ClearArrowsAtPosition(int end
)
2074 wxNode
*node
= m_arcArrows
.First();
2077 wxArrowHead
*arrow
= (wxArrowHead
*)node
->Data();
2078 wxNode
*next
= node
->Next();
2087 case ARROW_POSITION_START
:
2089 if (arrow
->GetArrowEnd() == ARROW_POSITION_START
)
2096 case ARROW_POSITION_END
:
2098 if (arrow
->GetArrowEnd() == ARROW_POSITION_END
)
2105 case ARROW_POSITION_MIDDLE
:
2107 if (arrow
->GetArrowEnd() == ARROW_POSITION_MIDDLE
)
2119 bool wxLineShape::ClearArrow(const wxString
& name
)
2121 wxNode
*node
= m_arcArrows
.First();
2124 wxArrowHead
*arrow
= (wxArrowHead
*)node
->Data();
2125 if (arrow
->GetName() == name
)
2131 node
= node
->Next();
2137 * Finds an arrowhead at the given position (if -1, any position)
2141 wxArrowHead
*wxLineShape::FindArrowHead(int position
, const wxString
& name
)
2143 wxNode
*node
= m_arcArrows
.First();
2146 wxArrowHead
*arrow
= (wxArrowHead
*)node
->Data();
2147 if (((position
== -1) || (position
== arrow
->GetArrowEnd())) &&
2148 (arrow
->GetName() == name
))
2150 node
= node
->Next();
2155 wxArrowHead
*wxLineShape::FindArrowHead(long arrowId
)
2157 wxNode
*node
= m_arcArrows
.First();
2160 wxArrowHead
*arrow
= (wxArrowHead
*)node
->Data();
2161 if (arrowId
== arrow
->GetId())
2163 node
= node
->Next();
2169 * Deletes an arrowhead at the given position (if -1, any position)
2173 bool wxLineShape::DeleteArrowHead(int position
, const wxString
& name
)
2175 wxNode
*node
= m_arcArrows
.First();
2178 wxArrowHead
*arrow
= (wxArrowHead
*)node
->Data();
2179 if (((position
== -1) || (position
== arrow
->GetArrowEnd())) &&
2180 (arrow
->GetName() == name
))
2186 node
= node
->Next();
2191 // Overloaded DeleteArrowHead: pass arrowhead id.
2192 bool wxLineShape::DeleteArrowHead(long id
)
2194 wxNode
*node
= m_arcArrows
.First();
2197 wxArrowHead
*arrow
= (wxArrowHead
*)node
->Data();
2198 if (arrow
->GetId() == id
)
2204 node
= node
->Next();
2210 * Calculate the minimum width a line
2211 * occupies, for the purposes of drawing lines in tools.
2215 float wxLineShape::FindMinimumWidth()
2217 float minWidth
= 0.0;
2218 wxNode
*node
= m_arcArrows
.First();
2221 wxArrowHead
*arrowHead
= (wxArrowHead
*)node
->Data();
2222 minWidth
+= arrowHead
->GetSize();
2224 minWidth
+= arrowHead
->GetSpacing();
2226 node
= node
->Next();
2228 // We have ABSOLUTE minimum now. So
2229 // scale it to give it reasonable aesthetics
2230 // when drawing with line.
2232 minWidth
= (float)(minWidth
* 1.4);
2236 SetEnds(0.0, 0.0, minWidth
, 0.0);
2242 // Find which position we're talking about at this (x, y).
2243 // Returns ARROW_POSITION_START, ARROW_POSITION_MIDDLE, ARROW_POSITION_END
2244 int wxLineShape::FindLinePosition(float x
, float y
)
2246 float startX
, startY
, endX
, endY
;
2247 GetEnds(&startX
, &startY
, &endX
, &endY
);
2249 // Find distances from centre, start and end. The smallest wins.
2250 float centreDistance
= (float)(sqrt((x
- m_xpos
)*(x
- m_xpos
) + (y
- m_ypos
)*(y
- m_ypos
)));
2251 float startDistance
= (float)(sqrt((x
- startX
)*(x
- startX
) + (y
- startY
)*(y
- startY
)));
2252 float endDistance
= (float)(sqrt((x
- endX
)*(x
- endX
) + (y
- endY
)*(y
- endY
)));
2254 if (centreDistance
< startDistance
&& centreDistance
< endDistance
)
2255 return ARROW_POSITION_MIDDLE
;
2256 else if (startDistance
< endDistance
)
2257 return ARROW_POSITION_START
;
2259 return ARROW_POSITION_END
;
2262 // Set alignment flags
2263 void wxLineShape::SetAlignmentOrientation(bool isEnd
, bool isHoriz
)
2267 if (isHoriz
&& ((m_alignmentEnd
& LINE_ALIGNMENT_HORIZ
) != LINE_ALIGNMENT_HORIZ
))
2268 m_alignmentEnd
|= LINE_ALIGNMENT_HORIZ
;
2269 else if (!isHoriz
&& ((m_alignmentEnd
& LINE_ALIGNMENT_HORIZ
) == LINE_ALIGNMENT_HORIZ
))
2270 m_alignmentEnd
-= LINE_ALIGNMENT_HORIZ
;
2274 if (isHoriz
&& ((m_alignmentStart
& LINE_ALIGNMENT_HORIZ
) != LINE_ALIGNMENT_HORIZ
))
2275 m_alignmentStart
|= LINE_ALIGNMENT_HORIZ
;
2276 else if (!isHoriz
&& ((m_alignmentStart
& LINE_ALIGNMENT_HORIZ
) == LINE_ALIGNMENT_HORIZ
))
2277 m_alignmentStart
-= LINE_ALIGNMENT_HORIZ
;
2281 void wxLineShape::SetAlignmentType(bool isEnd
, int alignType
)
2285 if (alignType
== LINE_ALIGNMENT_TO_NEXT_HANDLE
)
2287 if ((m_alignmentEnd
& LINE_ALIGNMENT_TO_NEXT_HANDLE
) != LINE_ALIGNMENT_TO_NEXT_HANDLE
)
2288 m_alignmentEnd
|= LINE_ALIGNMENT_TO_NEXT_HANDLE
;
2290 else if ((m_alignmentEnd
& LINE_ALIGNMENT_TO_NEXT_HANDLE
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
)
2291 m_alignmentEnd
-= LINE_ALIGNMENT_TO_NEXT_HANDLE
;
2295 if (alignType
== LINE_ALIGNMENT_TO_NEXT_HANDLE
)
2297 if ((m_alignmentStart
& LINE_ALIGNMENT_TO_NEXT_HANDLE
) != LINE_ALIGNMENT_TO_NEXT_HANDLE
)
2298 m_alignmentStart
|= LINE_ALIGNMENT_TO_NEXT_HANDLE
;
2300 else if ((m_alignmentStart
& LINE_ALIGNMENT_TO_NEXT_HANDLE
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
)
2301 m_alignmentStart
-= LINE_ALIGNMENT_TO_NEXT_HANDLE
;
2305 bool wxLineShape::GetAlignmentOrientation(bool isEnd
)
2308 return ((m_alignmentEnd
& LINE_ALIGNMENT_HORIZ
) == LINE_ALIGNMENT_HORIZ
);
2310 return ((m_alignmentStart
& LINE_ALIGNMENT_HORIZ
) == LINE_ALIGNMENT_HORIZ
);
2313 int wxLineShape::GetAlignmentType(bool isEnd
)
2316 return (m_alignmentEnd
& LINE_ALIGNMENT_TO_NEXT_HANDLE
);
2318 return (m_alignmentStart
& LINE_ALIGNMENT_TO_NEXT_HANDLE
);
2321 wxRealPoint
*wxLineShape::GetNextControlPoint(wxShape
*nodeObject
)
2323 int n
= m_lineControlPoints
->Number();
2325 if (m_to
== nodeObject
)
2327 // Must be END of line, so we want (n - 1)th control point.
2328 // But indexing ends at n-1, so subtract 2.
2332 wxNode
*node
= m_lineControlPoints
->Nth(nn
);
2335 return (wxRealPoint
*)node
->Data();
2346 IMPLEMENT_DYNAMIC_CLASS(wxArrowHead
, wxObject
)
2348 wxArrowHead::wxArrowHead(WXTYPE type
, int end
, float size
, float dist
, const wxString
& name
,
2349 wxPseudoMetaFile
*mf
, long arrowId
)
2351 m_arrowType
= type
; m_arrowEnd
= end
; m_arrowSize
= size
;
2363 wxArrowHead::wxArrowHead(wxArrowHead
& toCopy
)
2365 m_arrowType
= toCopy
.m_arrowType
; m_arrowEnd
= toCopy
.GetArrowEnd();
2366 m_arrowSize
= toCopy
.m_arrowSize
;
2367 m_xOffset
= toCopy
.m_xOffset
;
2368 m_yOffset
= toCopy
.m_yOffset
;
2369 m_spacing
= toCopy
.m_spacing
;
2370 m_arrowName
= toCopy
.m_arrowName
;
2371 if (toCopy
.m_metaFile
)
2372 m_metaFile
= new wxPseudoMetaFile(*(toCopy
.m_metaFile
));
2378 wxArrowHead::~wxArrowHead()
2380 if (m_metaFile
) delete m_metaFile
;
2383 void wxArrowHead::SetSize(float size
)
2386 if ((m_arrowType
== ARROW_METAFILE
) && m_metaFile
)
2388 float oldWidth
= m_metaFile
->m_width
;
2389 if (oldWidth
== 0.0)
2392 float scale
= (float)(size
/oldWidth
);
2394 m_metaFile
->Scale(scale
, scale
);
2403 IMPLEMENT_DYNAMIC_CLASS(wxLabelShape
, wxRectangleShape
)
2405 wxLabelShape::wxLabelShape(wxLineShape
*parent
, wxShapeRegion
*region
, float w
, float h
):wxRectangleShape(w
, h
)
2407 m_lineShape
= parent
;
2408 m_shapeRegion
= region
;
2409 SetPen(wxThePenList
->FindOrCreatePen(wxColour(0, 0, 0), 1, wxDOT
));
2412 wxLabelShape::~wxLabelShape()
2416 void wxLabelShape::OnDraw(wxDC
& dc
)
2418 if (m_lineShape
&& !m_lineShape
->GetDrawHandles())
2421 float x1
= (float)(m_xpos
- m_width
/2.0);
2422 float y1
= (float)(m_ypos
- m_height
/2.0);
2426 if (m_pen
->GetWidth() == 0)
2427 dc
.SetPen(transparent_pen
);
2431 dc
.SetBrush(wxTRANSPARENT_BRUSH
);
2433 if (m_cornerRadius
> 0.0)
2434 dc
.DrawRoundedRectangle(x1
, y1
, m_width
, m_height
, m_cornerRadius
);
2436 dc
.DrawRectangle(x1
, y1
, m_width
, m_height
);
2439 void wxLabelShape::OnDrawContents(wxDC
& dc
)
2443 void wxLabelShape::OnDragLeft(bool draw
, float x
, float y
, int keys
, int attachment
)
2445 wxRectangleShape::OnDragLeft(draw
, x
, y
, keys
, attachment
);
2448 void wxLabelShape::OnBeginDragLeft(float x
, float y
, int keys
, int attachment
)
2450 wxRectangleShape::OnBeginDragLeft(x
, y
, keys
, attachment
);
2453 void wxLabelShape::OnEndDragLeft(float x
, float y
, int keys
, int attachment
)
2455 wxRectangleShape::OnEndDragLeft(x
, y
, keys
, attachment
);
2458 bool wxLabelShape::OnMovePre(wxDC
& dc
, float x
, float y
, float old_x
, float old_y
, bool display
)
2460 m_shapeRegion
->SetSize(m_width
, m_height
);
2462 // Find position in line's region list
2464 wxNode
*node
= m_lineShape
->GetRegions().First();
2467 if (m_shapeRegion
== (wxShapeRegion
*)node
->Data())
2471 node
= node
->Next();
2476 m_lineShape
->GetLabelPosition(i
, &xx
, &yy
);
2477 // Set the region's offset, relative to the default position for
2479 m_shapeRegion
->SetPosition((float)(x
- xx
), (float)(y
- yy
));
2481 // Need to reformat to fit region.
2482 if (m_shapeRegion
->GetText())
2485 wxString
s(m_shapeRegion
->GetText());
2486 m_lineShape
->FormatText(dc
, s
, i
);
2487 m_lineShape
->DrawRegion(dc
, m_shapeRegion
, xx
, yy
);
2492 // Divert left and right clicks to line object
2493 void wxLabelShape::OnLeftClick(float x
, float y
, int keys
, int attachment
)
2495 m_lineShape
->GetEventHandler()->OnLeftClick(x
, y
, keys
, attachment
);
2498 void wxLabelShape::OnRightClick(float x
, float y
, int keys
, int attachment
)
2500 m_lineShape
->GetEventHandler()->OnRightClick(x
, y
, keys
, attachment
);