1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxLineShape
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "lines.h"
14 #pragma implementation "linesp.h"
17 // For compilers that support precompilation, includes "wx.h".
18 #include "wx/wxprec.h"
29 #include <wx/deprecated/wxexpr.h>
39 #include "wx/ogl/ogl.h"
43 IMPLEMENT_DYNAMIC_CLASS(wxLineShape
, wxShape
)
45 wxLineShape::wxLineShape()
47 m_sensitivity
= OP_CLICK_LEFT
| OP_CLICK_RIGHT
;
52 m_actualTextWidth = 0.0;
53 m_actualTextHeight = 0.0;
58 m_arrowSpacing
= 5.0; // For the moment, don't bother saving this to file.
59 m_ignoreArrowOffsets
= FALSE
;
61 m_maintainStraightLines
= FALSE
;
65 m_lineControlPoints
= NULL
;
67 // Clear any existing regions (created in an earlier constructor)
68 // and make the three line regions.
70 wxShapeRegion
*newRegion
= new wxShapeRegion
;
71 newRegion
->SetName(wxT("Middle"));
72 newRegion
->SetSize(150, 50);
73 m_regions
.Append((wxObject
*)newRegion
);
75 newRegion
= new wxShapeRegion
;
76 newRegion
->SetName(wxT("Start"));
77 newRegion
->SetSize(150, 50);
78 m_regions
.Append((wxObject
*)newRegion
);
80 newRegion
= new wxShapeRegion
;
81 newRegion
->SetName(wxT("End"));
82 newRegion
->SetSize(150, 50);
83 m_regions
.Append((wxObject
*)newRegion
);
85 for (int i
= 0; i
< 3; i
++)
86 m_labelObjects
[i
] = NULL
;
89 wxLineShape::~wxLineShape()
91 if (m_lineControlPoints
)
93 ClearPointList(*m_lineControlPoints
);
94 delete m_lineControlPoints
;
96 for (int i
= 0; i
< 3; i
++)
98 if (m_labelObjects
[i
])
100 m_labelObjects
[i
]->Select(FALSE
);
101 m_labelObjects
[i
]->RemoveFromCanvas(m_canvas
);
102 delete m_labelObjects
[i
];
103 m_labelObjects
[i
] = NULL
;
106 ClearArrowsAtPosition(-1);
109 void wxLineShape::MakeLineControlPoints(int n
)
111 if (m_lineControlPoints
)
113 ClearPointList(*m_lineControlPoints
);
114 delete m_lineControlPoints
;
116 m_lineControlPoints
= new wxList
;
118 for (int i
= 0; i
< n
; i
++)
120 wxRealPoint
*point
= new wxRealPoint(-999, -999);
121 m_lineControlPoints
->Append((wxObject
*) point
);
125 wxNode
*wxLineShape::InsertLineControlPoint(wxDC
* dc
)
130 wxNode
*last
= m_lineControlPoints
->GetLast();
131 wxNode
*second_last
= last
->GetPrevious();
132 wxRealPoint
*last_point
= (wxRealPoint
*)last
->GetData();
133 wxRealPoint
*second_last_point
= (wxRealPoint
*)second_last
->GetData();
135 // Choose a point half way between the last and penultimate points
136 double line_x
= ((last_point
->x
+ second_last_point
->x
)/2);
137 double line_y
= ((last_point
->y
+ second_last_point
->y
)/2);
139 wxRealPoint
*point
= new wxRealPoint(line_x
, line_y
);
140 wxNode
*node
= m_lineControlPoints
->Insert(last
, (wxObject
*) point
);
144 bool wxLineShape::DeleteLineControlPoint()
146 if (m_lineControlPoints
->GetCount() < 3)
149 wxNode
*last
= m_lineControlPoints
->GetLast();
150 wxNode
*second_last
= last
->GetPrevious();
152 wxRealPoint
*second_last_point
= (wxRealPoint
*)second_last
->GetData();
153 delete second_last_point
;
159 void wxLineShape::Initialise()
161 if (m_lineControlPoints
)
163 // Just move the first and last control points
164 wxNode
*first
= m_lineControlPoints
->GetFirst();
165 wxRealPoint
*first_point
= (wxRealPoint
*)first
->GetData();
167 wxNode
*last
= m_lineControlPoints
->GetLast();
168 wxRealPoint
*last_point
= (wxRealPoint
*)last
->GetData();
170 // If any of the line points are at -999, we must
171 // initialize them by placing them half way between the first
173 wxNode
*node
= first
->GetNext();
176 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
177 if (point
->x
== -999)
179 double x1
, y1
, x2
, y2
;
180 if (first_point
->x
< last_point
->x
)
181 { x1
= first_point
->x
; x2
= last_point
->x
; }
183 { x2
= first_point
->x
; x1
= last_point
->x
; }
185 if (first_point
->y
< last_point
->y
)
186 { y1
= first_point
->y
; y2
= last_point
->y
; }
188 { y2
= first_point
->y
; y1
= last_point
->y
; }
190 point
->x
= ((x2
- x1
)/2 + x1
);
191 point
->y
= ((y2
- y1
)/2 + y1
);
193 node
= node
->GetNext();
198 // Format a text string according to the region size, adding
199 // strings with positions to region text list
200 void wxLineShape::FormatText(wxDC
& dc
, const wxString
& s
, int i
)
205 if (m_regions
.GetCount() < 1)
207 wxNode
*node
= m_regions
.Item(i
);
211 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
213 dc
.SetFont(* region
->GetFont());
215 region
->GetSize(&w
, &h
);
216 // Initialize the size if zero
217 if (((w
== 0) || (h
== 0)) && (s
.Length() > 0))
220 region
->SetSize(w
, h
);
223 wxStringList
*string_list
= oglFormatText(dc
, s
, (w
-5), (h
-5), region
->GetFormatMode());
224 node
= (wxNode
*)string_list
->GetFirst();
227 wxChar
*s
= (wxChar
*)node
->GetData();
228 wxShapeTextLine
*line
= new wxShapeTextLine(0.0, 0.0, s
);
229 region
->GetFormattedText().Append((wxObject
*)line
);
230 node
= node
->GetNext();
235 if (region
->GetFormatMode() & FORMAT_SIZE_TO_CONTENTS
)
237 oglGetCentredTextExtent(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, w
, h
, &actualW
, &actualH
);
238 if ((actualW
!= w
) || (actualH
!= h
))
241 GetLabelPosition(i
, &xx
, &yy
);
242 EraseRegion(dc
, region
, xx
, yy
);
243 if (m_labelObjects
[i
])
245 m_labelObjects
[i
]->Select(FALSE
, &dc
);
246 m_labelObjects
[i
]->Erase(dc
);
247 m_labelObjects
[i
]->SetSize(actualW
, actualH
);
250 region
->SetSize(actualW
, actualH
);
252 if (m_labelObjects
[i
])
254 m_labelObjects
[i
]->Select(TRUE
, & dc
);
255 m_labelObjects
[i
]->Draw(dc
);
259 oglCentreText(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, actualW
, actualH
, region
->GetFormatMode());
263 void wxLineShape::DrawRegion(wxDC
& dc
, wxShapeRegion
*region
, double x
, double y
)
265 if (GetDisableLabel())
270 region
->GetSize(&w
, &h
);
272 // Get offset from x, y
273 region
->GetPosition(&xx
, &yy
);
278 // First, clear a rectangle for the text IF there is any
279 if (region
->GetFormattedText().GetCount() > 0)
281 dc
.SetPen(GetBackgroundPen());
282 dc
.SetBrush(GetBackgroundBrush());
285 if (region
->GetFont()) dc
.SetFont(* region
->GetFont());
287 dc
.DrawRectangle((long)(xp
- w
/2.0), (long)(yp
- h
/2.0), (long)w
, (long)h
);
289 if (m_pen
) dc
.SetPen(* m_pen
);
290 dc
.SetTextForeground(region
->GetActualColourObject());
293 dc
.SetTextBackground(GetBackgroundBrush().GetColour());
296 oglDrawFormattedText(dc
, &(region
->GetFormattedText()), xp
, yp
, w
, h
, region
->GetFormatMode());
300 void wxLineShape::EraseRegion(wxDC
& dc
, wxShapeRegion
*region
, double x
, double y
)
302 if (GetDisableLabel())
307 region
->GetSize(&w
, &h
);
309 // Get offset from x, y
310 region
->GetPosition(&xx
, &yy
);
315 if (region
->GetFormattedText().GetCount() > 0)
317 dc
.SetPen(GetBackgroundPen());
318 dc
.SetBrush(GetBackgroundBrush());
320 dc
.DrawRectangle((long)(xp
- w
/2.0), (long)(yp
- h
/2.0), (long)w
, (long)h
);
324 // Get the reference point for a label. Region x and y
325 // are offsets from this.
326 // position is 0, 1, 2
327 void wxLineShape::GetLabelPosition(int position
, double *x
, double *y
)
333 // Want to take the middle section for the label
334 int n
= m_lineControlPoints
->GetCount();
335 int half_way
= (int)(n
/2);
337 // Find middle of this line
338 wxNode
*node
= m_lineControlPoints
->Item(half_way
- 1);
339 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
340 wxNode
*next_node
= node
->GetNext();
341 wxRealPoint
*next_point
= (wxRealPoint
*)next_node
->GetData();
343 double dx
= (next_point
->x
- point
->x
);
344 double dy
= (next_point
->y
- point
->y
);
345 *x
= (double)(point
->x
+ dx
/2.0);
346 *y
= (double)(point
->y
+ dy
/2.0);
351 wxNode
*node
= m_lineControlPoints
->GetFirst();
352 *x
= ((wxRealPoint
*)node
->GetData())->x
;
353 *y
= ((wxRealPoint
*)node
->GetData())->y
;
358 wxNode
*node
= m_lineControlPoints
->GetLast();
359 *x
= ((wxRealPoint
*)node
->GetData())->x
;
360 *y
= ((wxRealPoint
*)node
->GetData())->y
;
369 * Find whether line is supposed to be vertical or horizontal and
373 void GraphicsStraightenLine(wxRealPoint
*point1
, wxRealPoint
*point2
)
375 double dx
= point2
->x
- point1
->x
;
376 double dy
= point2
->y
- point1
->y
;
380 else if (fabs(dy
/dx
) > 1.0)
382 point2
->x
= point1
->x
;
384 else point2
->y
= point1
->y
;
387 void wxLineShape::Straighten(wxDC
*dc
)
389 if (!m_lineControlPoints
|| m_lineControlPoints
->GetCount() < 3)
395 wxNode
*first_point_node
= m_lineControlPoints
->GetFirst();
396 wxNode
*last_point_node
= m_lineControlPoints
->GetLast();
397 wxNode
*second_last_point_node
= last_point_node
->GetPrevious();
399 wxRealPoint
*last_point
= (wxRealPoint
*)last_point_node
->GetData();
400 wxRealPoint
*second_last_point
= (wxRealPoint
*)second_last_point_node
->GetData();
402 GraphicsStraightenLine(last_point
, second_last_point
);
404 wxNode
*node
= first_point_node
;
405 while (node
&& (node
!= second_last_point_node
))
407 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
408 wxRealPoint
*next_point
= (wxRealPoint
*)(node
->GetNext()->GetData());
410 GraphicsStraightenLine(point
, next_point
);
411 node
= node
->GetNext();
419 void wxLineShape::Unlink()
422 m_to
->GetLines().DeleteObject(this);
424 m_from
->GetLines().DeleteObject(this);
429 void wxLineShape::SetEnds(double x1
, double y1
, double x2
, double y2
)
432 wxNode
*first_point_node
= m_lineControlPoints
->GetFirst();
433 wxNode
*last_point_node
= m_lineControlPoints
->GetLast();
434 wxRealPoint
*first_point
= (wxRealPoint
*)first_point_node
->GetData();
435 wxRealPoint
*last_point
= (wxRealPoint
*)last_point_node
->GetData();
442 m_xpos
= (double)((x1
+ x2
)/2.0);
443 m_ypos
= (double)((y1
+ y2
)/2.0);
446 // Get absolute positions of ends
447 void wxLineShape::GetEnds(double *x1
, double *y1
, double *x2
, double *y2
)
449 wxNode
*first_point_node
= m_lineControlPoints
->GetFirst();
450 wxNode
*last_point_node
= m_lineControlPoints
->GetLast();
451 wxRealPoint
*first_point
= (wxRealPoint
*)first_point_node
->GetData();
452 wxRealPoint
*last_point
= (wxRealPoint
*)last_point_node
->GetData();
454 *x1
= first_point
->x
; *y1
= first_point
->y
;
455 *x2
= last_point
->x
; *y2
= last_point
->y
;
458 void wxLineShape::SetAttachments(int from_attach
, int to_attach
)
460 m_attachmentFrom
= from_attach
;
461 m_attachmentTo
= to_attach
;
464 bool wxLineShape::HitTest(double x
, double y
, int *attachment
, double *distance
)
466 if (!m_lineControlPoints
)
469 // Look at label regions in case mouse is over a label
470 bool inLabelRegion
= FALSE
;
471 for (int i
= 0; i
< 3; i
++)
473 wxNode
*regionNode
= m_regions
.Item(i
);
476 wxShapeRegion
*region
= (wxShapeRegion
*)regionNode
->GetData();
477 if (region
->m_formattedText
.GetCount() > 0)
479 double xp
, yp
, cx
, cy
, cw
, ch
;
480 GetLabelPosition(i
, &xp
, &yp
);
481 // Offset region from default label position
482 region
->GetPosition(&cx
, &cy
);
483 region
->GetSize(&cw
, &ch
);
486 double rLeft
= (double)(cx
- (cw
/2.0));
487 double rTop
= (double)(cy
- (ch
/2.0));
488 double rRight
= (double)(cx
+ (cw
/2.0));
489 double rBottom
= (double)(cy
+ (ch
/2.0));
490 if (x
> rLeft
&& x
< rRight
&& y
> rTop
&& y
< rBottom
)
492 inLabelRegion
= TRUE
;
499 wxNode
*node
= m_lineControlPoints
->GetFirst();
501 while (node
&& node
->GetNext())
503 wxRealPoint
*point1
= (wxRealPoint
*)node
->GetData();
504 wxRealPoint
*point2
= (wxRealPoint
*)node
->GetNext()->GetData();
506 // For inaccurate mousing allow 8 pixel corridor
509 double dx
= point2
->x
- point1
->x
;
510 double dy
= point2
->y
- point1
->y
;
511 double seg_len
= sqrt(dx
*dx
+dy
*dy
);
512 double distance_from_seg
=
513 seg_len
*((x
-point1
->x
)*dy
-(y
-point1
->y
)*dx
)/(dy
*dy
+dx
*dx
);
514 double distance_from_prev
=
515 seg_len
*((y
-point1
->y
)*dy
+(x
-point1
->x
)*dx
)/(dy
*dy
+dx
*dx
);
517 if ((fabs(distance_from_seg
) < extra
&&
518 distance_from_prev
>= 0 && distance_from_prev
<= seg_len
)
522 *distance
= distance_from_seg
;
526 node
= node
->GetNext();
531 void wxLineShape::DrawArrows(wxDC
& dc
)
533 // Distance along line of each arrow: space them out evenly.
534 double startArrowPos
= 0.0;
535 double endArrowPos
= 0.0;
536 double middleArrowPos
= 0.0;
538 wxNode
*node
= m_arcArrows
.GetFirst();
541 wxArrowHead
*arrow
= (wxArrowHead
*)node
->GetData();
542 switch (arrow
->GetArrowEnd())
544 case ARROW_POSITION_START
:
546 if ((arrow
->GetXOffset() != 0.0) && !m_ignoreArrowOffsets
)
547 // If specified, x offset is proportional to line length
548 DrawArrow(dc
, arrow
, arrow
->GetXOffset(), TRUE
);
551 DrawArrow(dc
, arrow
, startArrowPos
, FALSE
); // Absolute distance
552 startArrowPos
+= arrow
->GetSize() + arrow
->GetSpacing();
556 case ARROW_POSITION_END
:
558 if ((arrow
->GetXOffset() != 0.0) && !m_ignoreArrowOffsets
)
559 DrawArrow(dc
, arrow
, arrow
->GetXOffset(), TRUE
);
562 DrawArrow(dc
, arrow
, endArrowPos
, FALSE
);
563 endArrowPos
+= arrow
->GetSize() + arrow
->GetSpacing();
567 case ARROW_POSITION_MIDDLE
:
569 arrow
->SetXOffset(middleArrowPos
);
570 if ((arrow
->GetXOffset() != 0.0) && !m_ignoreArrowOffsets
)
571 DrawArrow(dc
, arrow
, arrow
->GetXOffset(), TRUE
);
574 DrawArrow(dc
, arrow
, middleArrowPos
, FALSE
);
575 middleArrowPos
+= arrow
->GetSize() + arrow
->GetSpacing();
580 node
= node
->GetNext();
584 void wxLineShape::DrawArrow(wxDC
& dc
, wxArrowHead
*arrow
, double xOffset
, bool proportionalOffset
)
586 wxNode
*first_line_node
= m_lineControlPoints
->GetFirst();
587 wxRealPoint
*first_line_point
= (wxRealPoint
*)first_line_node
->GetData();
588 wxNode
*second_line_node
= first_line_node
->GetNext();
589 wxRealPoint
*second_line_point
= (wxRealPoint
*)second_line_node
->GetData();
591 wxNode
*last_line_node
= m_lineControlPoints
->GetLast();
592 wxRealPoint
*last_line_point
= (wxRealPoint
*)last_line_node
->GetData();
593 wxNode
*second_last_line_node
= last_line_node
->GetPrevious();
594 wxRealPoint
*second_last_line_point
= (wxRealPoint
*)second_last_line_node
->GetData();
596 // Position where we want to start drawing
597 double positionOnLineX
= 0.0, positionOnLineY
= 0.0;
599 // Position of start point of line, at the end of which we draw the arrow.
600 double startPositionX
= 0.0 , startPositionY
= 0.0;
602 switch (arrow
->GetPosition())
604 case ARROW_POSITION_START
:
606 // If we're using a proportional offset, calculate just where this will
608 double realOffset
= xOffset
;
609 if (proportionalOffset
)
612 (double)sqrt((second_line_point
->x
- first_line_point
->x
)*(second_line_point
->x
- first_line_point
->x
) +
613 (second_line_point
->y
- first_line_point
->y
)*(second_line_point
->y
- first_line_point
->y
));
614 realOffset
= (double)(xOffset
* totalLength
);
616 GetPointOnLine(second_line_point
->x
, second_line_point
->y
,
617 first_line_point
->x
, first_line_point
->y
,
618 realOffset
, &positionOnLineX
, &positionOnLineY
);
619 startPositionX
= second_line_point
->x
;
620 startPositionY
= second_line_point
->y
;
623 case ARROW_POSITION_END
:
625 // If we're using a proportional offset, calculate just where this will
627 double realOffset
= xOffset
;
628 if (proportionalOffset
)
631 (double)sqrt((second_last_line_point
->x
- last_line_point
->x
)*(second_last_line_point
->x
- last_line_point
->x
) +
632 (second_last_line_point
->y
- last_line_point
->y
)*(second_last_line_point
->y
- last_line_point
->y
));
633 realOffset
= (double)(xOffset
* totalLength
);
635 GetPointOnLine(second_last_line_point
->x
, second_last_line_point
->y
,
636 last_line_point
->x
, last_line_point
->y
,
637 realOffset
, &positionOnLineX
, &positionOnLineY
);
638 startPositionX
= second_last_line_point
->x
;
639 startPositionY
= second_last_line_point
->y
;
642 case ARROW_POSITION_MIDDLE
:
644 // Choose a point half way between the last and penultimate points
645 double x
= ((last_line_point
->x
+ second_last_line_point
->x
)/2);
646 double y
= ((last_line_point
->y
+ second_last_line_point
->y
)/2);
648 // If we're using a proportional offset, calculate just where this will
650 double realOffset
= xOffset
;
651 if (proportionalOffset
)
654 (double)sqrt((second_last_line_point
->x
- x
)*(second_last_line_point
->x
- x
) +
655 (second_last_line_point
->y
- y
)*(second_last_line_point
->y
- y
));
656 realOffset
= (double)(xOffset
* totalLength
);
659 GetPointOnLine(second_last_line_point
->x
, second_last_line_point
->y
,
660 x
, y
, realOffset
, &positionOnLineX
, &positionOnLineY
);
661 startPositionX
= second_last_line_point
->x
;
662 startPositionY
= second_last_line_point
->y
;
668 * Add yOffset to arrow, if any
671 const double myPi
= (double) 3.14159265;
672 // The translation that the y offset may give
675 if ((arrow
->GetYOffset() != 0.0) && !m_ignoreArrowOffsets
)
681 (x1, y1)--------------(x3, y3)------------------(x2, y2)
682 x4 = x3 - d * sin(theta)
683 y4 = y3 + d * cos(theta)
685 Where theta = tan(-1) of (y3-y1)/(x3-x1)
687 double x1
= startPositionX
;
688 double y1
= startPositionY
;
689 double x3
= positionOnLineX
;
690 double y3
= positionOnLineY
;
691 double d
= -arrow
->GetYOffset(); // Negate so +offset is above line
695 theta
= (double)(myPi
/2.0);
697 theta
= (double)atan((y3
-y1
)/(x3
-x1
));
699 double x4
= (double)(x3
- (d
*sin(theta
)));
700 double y4
= (double)(y3
+ (d
*cos(theta
)));
702 deltaX
= x4
- positionOnLineX
;
703 deltaY
= y4
- positionOnLineY
;
706 switch (arrow
->_GetType())
710 double arrowLength
= arrow
->GetSize();
711 double arrowWidth
= (double)(arrowLength
/3.0);
713 double tip_x
, tip_y
, side1_x
, side1_y
, side2_x
, side2_y
;
714 oglGetArrowPoints(startPositionX
+deltaX
, startPositionY
+deltaY
,
715 positionOnLineX
+deltaX
, positionOnLineY
+deltaY
,
716 arrowLength
, arrowWidth
, &tip_x
, &tip_y
,
717 &side1_x
, &side1_y
, &side2_x
, &side2_y
);
720 points
[0].x
= (int) tip_x
; points
[0].y
= (int) tip_y
;
721 points
[1].x
= (int) side1_x
; points
[1].y
= (int) side1_y
;
722 points
[2].x
= (int) side2_x
; points
[2].y
= (int) side2_y
;
723 points
[3].x
= (int) tip_x
; points
[3].y
= (int) tip_y
;
726 dc
.SetBrush(* m_brush
);
727 dc
.DrawPolygon(4, points
);
730 case ARROW_HOLLOW_CIRCLE
:
731 case ARROW_FILLED_CIRCLE
:
733 // Find point on line of centre of circle, which is a radius away
734 // from the end position
735 double diameter
= (double)(arrow
->GetSize());
737 GetPointOnLine(startPositionX
+deltaX
, startPositionY
+deltaY
,
738 positionOnLineX
+deltaX
, positionOnLineY
+deltaY
,
739 (double)(diameter
/2.0),
742 // Convert ellipse centre to top-left coordinates
743 double x1
= (double)(x
- (diameter
/2.0));
744 double y1
= (double)(y
- (diameter
/2.0));
747 if (arrow
->_GetType() == ARROW_HOLLOW_CIRCLE
)
748 dc
.SetBrush(GetBackgroundBrush());
750 dc
.SetBrush(* m_brush
);
752 dc
.DrawEllipse((long) x1
, (long) y1
, (long) diameter
, (long) diameter
);
755 case ARROW_SINGLE_OBLIQUE
:
761 if (arrow
->GetMetaFile())
763 // Find point on line of centre of object, which is a half-width away
764 // from the end position
767 * <-- start pos <-----><-- positionOnLineX
769 * --------------| x | <-- e.g. rectangular arrowhead
773 GetPointOnLine(startPositionX
, startPositionY
,
774 positionOnLineX
, positionOnLineY
,
775 (double)(arrow
->GetMetaFile()->m_width
/2.0),
778 // Calculate theta for rotating the metafile.
781 | o(x2, y2) 'o' represents the arrowhead.
786 |______________________
789 double x1
= startPositionX
;
790 double y1
= startPositionY
;
791 double x2
= positionOnLineX
;
792 double y2
= positionOnLineY
;
794 if ((x1
== x2
) && (y1
== y2
))
797 else if ((x1
== x2
) && (y1
> y2
))
798 theta
= (double)(3.0*myPi
/2.0);
800 else if ((x1
== x2
) && (y2
> y1
))
801 theta
= (double)(myPi
/2.0);
803 else if ((x2
> x1
) && (y2
>= y1
))
804 theta
= (double)atan((y2
- y1
)/(x2
- x1
));
807 theta
= (double)(myPi
+ atan((y2
- y1
)/(x2
- x1
)));
809 else if ((x2
> x1
) && (y2
< y1
))
810 theta
= (double)(2*myPi
+ atan((y2
- y1
)/(x2
- x1
)));
814 wxLogFatalError(wxT("Unknown arrowhead rotation case in lines.cc"));
817 // Rotate about the centre of the object, then place
818 // the object on the line.
819 if (arrow
->GetMetaFile()->GetRotateable())
820 arrow
->GetMetaFile()->Rotate(0.0, 0.0, theta
);
824 // If erasing, just draw a rectangle.
825 double minX
, minY
, maxX
, maxY
;
826 arrow
->GetMetaFile()->GetBounds(&minX
, &minY
, &maxX
, &maxY
);
827 // Make erasing rectangle slightly bigger or you get droppings.
829 dc
.DrawRectangle((long)(deltaX
+ x
+ minX
- (extraPixels
/2.0)), (long)(deltaY
+ y
+ minY
- (extraPixels
/2.0)),
830 (long)(maxX
- minX
+ extraPixels
), (long)(maxY
- minY
+ extraPixels
));
833 arrow
->GetMetaFile()->Draw(dc
, x
+deltaX
, y
+deltaY
);
843 void wxLineShape::OnErase(wxDC
& dc
)
845 wxPen
*old_pen
= m_pen
;
846 wxBrush
*old_brush
= m_brush
;
847 wxPen bg_pen
= GetBackgroundPen();
848 wxBrush bg_brush
= GetBackgroundBrush();
852 double bound_x
, bound_y
;
853 GetBoundingBoxMax(&bound_x
, &bound_y
);
854 if (m_font
) dc
.SetFont(* m_font
);
856 // Undraw text regions
857 for (int i
= 0; i
< 3; i
++)
859 wxNode
*node
= m_regions
.Item(i
);
863 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
864 GetLabelPosition(i
, &x
, &y
);
865 EraseRegion(dc
, region
, x
, y
);
870 dc
.SetPen(GetBackgroundPen());
871 dc
.SetBrush(GetBackgroundBrush());
873 // Drawing over the line only seems to work if the line has a thickness
875 if (old_pen
&& (old_pen
->GetWidth() > 1))
877 dc
.DrawRectangle((long)(m_xpos
- (bound_x
/2.0) - 2.0), (long)(m_ypos
- (bound_y
/2.0) - 2.0),
878 (long)(bound_x
+4.0), (long)(bound_y
+4.0));
883 GetEventHandler()->OnDraw(dc
);
884 GetEventHandler()->OnEraseControlPoints(dc
);
888 if (old_pen
) SetPen(old_pen
);
889 if (old_brush
) SetBrush(old_brush
);
892 void wxLineShape::GetBoundingBoxMin(double *w
, double *h
)
899 wxNode
*node
= m_lineControlPoints
->GetFirst();
902 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
904 if (point
->x
< x1
) x1
= point
->x
;
905 if (point
->y
< y1
) y1
= point
->y
;
906 if (point
->x
> x2
) x2
= point
->x
;
907 if (point
->y
> y2
) y2
= point
->y
;
909 node
= node
->GetNext();
911 *w
= (double)(x2
- x1
);
912 *h
= (double)(y2
- y1
);
916 * For a node image of interest, finds the position of this arc
917 * amongst all the arcs which are attached to THIS SIDE of the node image,
918 * and the number of same.
920 void wxLineShape::FindNth(wxShape
*image
, int *nth
, int *no_arcs
, bool incoming
)
924 wxNode
*node
= image
->GetLines().GetFirst();
927 this_attachment
= m_attachmentTo
;
929 this_attachment
= m_attachmentFrom
;
931 // Find number of lines going into/out of this particular attachment point
934 wxLineShape
*line
= (wxLineShape
*)node
->GetData();
936 if (line
->m_from
== image
)
938 // This is the nth line attached to 'image'
939 if ((line
== this) && !incoming
)
942 // Increment num count if this is the same side (attachment number)
943 if (line
->m_attachmentFrom
== this_attachment
)
947 if (line
->m_to
== image
)
949 // This is the nth line attached to 'image'
950 if ((line
== this) && incoming
)
953 // Increment num count if this is the same side (attachment number)
954 if (line
->m_attachmentTo
== this_attachment
)
958 node
= node
->GetNext();
964 void wxLineShape::OnDrawOutline(wxDC
& dc
, double WXUNUSED(x
), double WXUNUSED(y
), double WXUNUSED(w
), double WXUNUSED(h
))
966 wxPen
*old_pen
= m_pen
;
967 wxBrush
*old_brush
= m_brush
;
969 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
971 SetBrush( wxTRANSPARENT_BRUSH
);
973 GetEventHandler()->OnDraw(dc
);
975 if (old_pen
) SetPen(old_pen
);
977 if (old_brush
) SetBrush(old_brush
);
981 bool wxLineShape::OnMovePre(wxDC
& dc
, double x
, double y
, double old_x
, double old_y
, bool WXUNUSED(display
))
983 double x_offset
= x
- old_x
;
984 double y_offset
= y
- old_y
;
986 if (m_lineControlPoints
&& !(x_offset
== 0.0 && y_offset
== 0.0))
988 wxNode
*node
= m_lineControlPoints
->GetFirst();
991 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
992 point
->x
+= x_offset
;
993 point
->y
+= y_offset
;
994 node
= node
->GetNext();
999 // Move temporary label rectangles if necessary
1000 for (int i
= 0; i
< 3; i
++)
1002 if (m_labelObjects
[i
])
1004 m_labelObjects
[i
]->Erase(dc
);
1005 double xp
, yp
, xr
, yr
;
1006 GetLabelPosition(i
, &xp
, &yp
);
1007 wxNode
*node
= m_regions
.Item(i
);
1010 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
1011 region
->GetPosition(&xr
, &yr
);
1018 m_labelObjects
[i
]->Move(dc
, xp
+xr
, yp
+yr
);
1024 void wxLineShape::OnMoveLink(wxDC
& dc
, bool moveControlPoints
)
1026 if (!m_from
|| !m_to
)
1029 if (m_lineControlPoints
->GetCount() > 2)
1032 // Do each end - nothing in the middle. User has to move other points
1033 // manually if necessary.
1034 double end_x
, end_y
;
1035 double other_end_x
, other_end_y
;
1037 FindLineEndPoints(&end_x
, &end_y
, &other_end_x
, &other_end_y
);
1039 wxNode
*first
= m_lineControlPoints
->GetFirst();
1040 /* wxRealPoint *first_point = */ (wxRealPoint
*)first
->GetData();
1041 wxNode
*last
= m_lineControlPoints
->GetLast();
1042 /* wxRealPoint *last_point = */ (wxRealPoint
*)last
->GetData();
1044 /* This is redundant, surely? Done by SetEnds.
1045 first_point->x = end_x; first_point->y = end_y;
1046 last_point->x = other_end_x; last_point->y = other_end_y;
1049 double oldX
= m_xpos
;
1050 double oldY
= m_ypos
;
1052 SetEnds(end_x
, end_y
, other_end_x
, other_end_y
);
1054 // Do a second time, because one may depend on the other.
1055 FindLineEndPoints(&end_x
, &end_y
, &other_end_x
, &other_end_y
);
1056 SetEnds(end_x
, end_y
, other_end_x
, other_end_y
);
1058 // Try to move control points with the arc
1059 double x_offset
= m_xpos
- oldX
;
1060 double y_offset
= m_ypos
- oldY
;
1062 // if (moveControlPoints && m_lineControlPoints && !(x_offset == 0.0 && y_offset == 0.0))
1063 // Only move control points if it's a self link. And only works if attachment mode is ON.
1064 if ((m_from
== m_to
) && (m_from
->GetAttachmentMode() != ATTACHMENT_MODE_NONE
) && moveControlPoints
&& m_lineControlPoints
&& !(x_offset
== 0.0 && y_offset
== 0.0))
1066 wxNode
*node
= m_lineControlPoints
->GetFirst();
1069 if ((node
!= m_lineControlPoints
->GetFirst()) && (node
!= m_lineControlPoints
->GetLast()))
1071 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
1072 point
->x
+= x_offset
;
1073 point
->y
+= y_offset
;
1075 node
= node
->GetNext();
1079 Move(dc
, m_xpos
, m_ypos
);
1082 // Finds the x, y points at the two ends of the line.
1083 // This function can be used by e.g. line-routing routines to
1084 // get the actual points on the two node images where the lines will be drawn
1086 void wxLineShape::FindLineEndPoints(double *fromX
, double *fromY
, double *toX
, double *toY
)
1088 if (!m_from
|| !m_to
)
1091 // Do each end - nothing in the middle. User has to move other points
1092 // manually if necessary.
1093 double end_x
= 0.0, end_y
= 0.0;
1094 double other_end_x
= 0.0, other_end_y
= 0.0;
1096 wxNode
*first
= m_lineControlPoints
->GetFirst();
1097 /* wxRealPoint *first_point = */ (wxRealPoint
*)first
->GetData();
1098 wxNode
*last
= m_lineControlPoints
->GetLast();
1099 /* wxRealPoint *last_point = */ (wxRealPoint
*)last
->GetData();
1101 wxNode
*second
= first
->GetNext();
1102 wxRealPoint
*second_point
= (wxRealPoint
*)second
->GetData();
1104 wxNode
*second_last
= last
->GetPrevious();
1105 wxRealPoint
*second_last_point
= (wxRealPoint
*)second_last
->GetData();
1107 if (m_lineControlPoints
->GetCount() > 2)
1109 if (m_from
->GetAttachmentMode() != ATTACHMENT_MODE_NONE
)
1112 FindNth(m_from
, &nth
, &no_arcs
, FALSE
); // Not incoming
1113 m_from
->GetAttachmentPosition(m_attachmentFrom
, &end_x
, &end_y
, nth
, no_arcs
, this);
1116 (void) m_from
->GetPerimeterPoint(m_from
->GetX(), m_from
->GetY(),
1117 (double)second_point
->x
, (double)second_point
->y
,
1120 if (m_to
->GetAttachmentMode() != ATTACHMENT_MODE_NONE
)
1123 FindNth(m_to
, &nth
, &no_arcs
, TRUE
); // Incoming
1124 m_to
->GetAttachmentPosition(m_attachmentTo
, &other_end_x
, &other_end_y
, nth
, no_arcs
, this);
1127 (void) m_to
->GetPerimeterPoint(m_to
->GetX(), m_to
->GetY(),
1128 (double)second_last_point
->x
, (double)second_last_point
->y
,
1129 &other_end_x
, &other_end_y
);
1133 double fromX
= m_from
->GetX();
1134 double fromY
= m_from
->GetY();
1135 double toX
= m_to
->GetX();
1136 double toY
= m_to
->GetY();
1138 if (m_from
->GetAttachmentMode() != ATTACHMENT_MODE_NONE
)
1141 FindNth(m_from
, &nth
, &no_arcs
, FALSE
);
1142 m_from
->GetAttachmentPosition(m_attachmentFrom
, &end_x
, &end_y
, nth
, no_arcs
, this);
1147 if (m_to
->GetAttachmentMode() != ATTACHMENT_MODE_NONE
)
1150 FindNth(m_to
, &nth
, &no_arcs
, TRUE
);
1151 m_to
->GetAttachmentPosition(m_attachmentTo
, &other_end_x
, &other_end_y
, nth
, no_arcs
, this);
1156 if (m_from
->GetAttachmentMode() == ATTACHMENT_MODE_NONE
)
1157 (void) m_from
->GetPerimeterPoint(m_from
->GetX(), m_from
->GetY(),
1161 if (m_to
->GetAttachmentMode() == ATTACHMENT_MODE_NONE
)
1162 (void) m_to
->GetPerimeterPoint(m_to
->GetX(), m_to
->GetY(),
1164 &other_end_x
, &other_end_y
);
1172 void wxLineShape::OnDraw(wxDC
& dc
)
1174 if (m_lineControlPoints
)
1179 dc
.SetBrush(* m_brush
);
1181 int n
= m_lineControlPoints
->GetCount();
1182 wxPoint
*points
= new wxPoint
[n
];
1184 for (i
= 0; i
< n
; i
++)
1186 wxRealPoint
* point
= (wxRealPoint
*) m_lineControlPoints
->Item(i
)->GetData();
1187 points
[i
].x
= WXROUND(point
->x
);
1188 points
[i
].y
= WXROUND(point
->y
);
1192 dc
.DrawSpline(n
, points
);
1194 dc
.DrawLines(n
, points
);
1197 // For some reason, last point isn't drawn under Windows.
1198 dc
.DrawPoint(points
[n
-1]);
1204 // Problem with pen - if not a solid pen, does strange things
1205 // to the arrowhead. So make (get) a new pen that's solid.
1206 if (m_pen
&& (m_pen
->GetStyle() != wxSOLID
))
1209 wxThePenList
->FindOrCreatePen(m_pen
->GetColour(), 1, wxSOLID
);
1211 dc
.SetPen(* solid_pen
);
1217 void wxLineShape::OnDrawControlPoints(wxDC
& dc
)
1222 // Draw temporary label rectangles if necessary
1223 for (int i
= 0; i
< 3; i
++)
1225 if (m_labelObjects
[i
])
1226 m_labelObjects
[i
]->Draw(dc
);
1228 wxShape::OnDrawControlPoints(dc
);
1231 void wxLineShape::OnEraseControlPoints(wxDC
& dc
)
1233 // Erase temporary label rectangles if necessary
1234 for (int i
= 0; i
< 3; i
++)
1236 if (m_labelObjects
[i
])
1237 m_labelObjects
[i
]->Erase(dc
);
1239 wxShape::OnEraseControlPoints(dc
);
1242 void wxLineShape::OnDragLeft(bool WXUNUSED(draw
), double WXUNUSED(x
), double WXUNUSED(y
), int WXUNUSED(keys
), int WXUNUSED(attachment
))
1246 void wxLineShape::OnBeginDragLeft(double WXUNUSED(x
), double WXUNUSED(y
), int WXUNUSED(keys
), int WXUNUSED(attachment
))
1250 void wxLineShape::OnEndDragLeft(double WXUNUSED(x
), double WXUNUSED(y
), int WXUNUSED(keys
), int WXUNUSED(attachment
))
1255 void wxLineShape::SetArrowSize(double length, double width)
1257 arrow_length = length;
1258 arrow_width = width;
1261 void wxLineShape::SetStartArrow(int style)
1263 start_style = style;
1266 void wxLineShape::SetMiddleArrow(int style)
1268 middle_style = style;
1271 void wxLineShape::SetEndArrow(int style)
1277 void wxLineShape::OnDrawContents(wxDC
& dc
)
1279 if (GetDisableLabel())
1282 for (int i
= 0; i
< 3; i
++)
1284 wxNode
*node
= m_regions
.Item(i
);
1287 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
1289 GetLabelPosition(i
, &x
, &y
);
1290 DrawRegion(dc
, region
, x
, y
);
1295 void wxLineShape::SetTo(wxShape
*object
)
1300 void wxLineShape::SetFrom(wxShape
*object
)
1305 void wxLineShape::MakeControlPoints()
1307 if (m_canvas
&& m_lineControlPoints
)
1309 wxNode
*first
= m_lineControlPoints
->GetFirst();
1310 wxNode
*last
= m_lineControlPoints
->GetLast();
1311 wxRealPoint
*first_point
= (wxRealPoint
*)first
->GetData();
1312 wxRealPoint
*last_point
= (wxRealPoint
*)last
->GetData();
1314 wxLineControlPoint
*control
= new wxLineControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
,
1315 first_point
->x
, first_point
->y
,
1316 CONTROL_POINT_ENDPOINT_FROM
);
1317 control
->m_point
= first_point
;
1318 m_canvas
->AddShape(control
);
1319 m_controlPoints
.Append(control
);
1322 wxNode
*node
= first
->GetNext();
1323 while (node
!= last
)
1325 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
1327 control
= new wxLineControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
,
1329 CONTROL_POINT_LINE
);
1330 control
->m_point
= point
;
1332 m_canvas
->AddShape(control
);
1333 m_controlPoints
.Append(control
);
1335 node
= node
->GetNext();
1337 control
= new wxLineControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
,
1338 last_point
->x
, last_point
->y
,
1339 CONTROL_POINT_ENDPOINT_TO
);
1340 control
->m_point
= last_point
;
1341 m_canvas
->AddShape(control
);
1342 m_controlPoints
.Append(control
);
1348 void wxLineShape::ResetControlPoints()
1350 if (m_canvas
&& m_lineControlPoints
&& m_controlPoints
.GetCount() > 0)
1352 wxNode
*node
= m_controlPoints
.GetFirst();
1353 wxNode
*control_node
= m_lineControlPoints
->GetFirst();
1354 while (node
&& control_node
)
1356 wxRealPoint
*point
= (wxRealPoint
*)control_node
->GetData();
1357 wxLineControlPoint
*control
= (wxLineControlPoint
*)node
->GetData();
1358 control
->SetX(point
->x
);
1359 control
->SetY(point
->y
);
1361 node
= node
->GetNext();
1362 control_node
= control_node
->GetNext();
1368 void wxLineShape::WriteAttributes(wxExpr
*clause
)
1370 wxShape::WriteAttributes(clause
);
1373 clause
->AddAttributeValue(_T("from"), m_from
->GetId());
1375 clause
->AddAttributeValue(_T("to"), m_to
->GetId());
1377 if (m_attachmentTo
!= 0)
1378 clause
->AddAttributeValue(_T("attachment_to"), (long)m_attachmentTo
);
1379 if (m_attachmentFrom
!= 0)
1380 clause
->AddAttributeValue(_T("attachment_from"), (long)m_attachmentFrom
);
1382 if (m_alignmentStart
!= 0)
1383 clause
->AddAttributeValue(_T("align_start"), (long)m_alignmentStart
);
1384 if (m_alignmentEnd
!= 0)
1385 clause
->AddAttributeValue(_T("align_end"), (long)m_alignmentEnd
);
1387 clause
->AddAttributeValue(_T("is_spline"), (long)m_isSpline
);
1388 if (m_maintainStraightLines
)
1389 clause
->AddAttributeValue(_T("keep_lines_straight"), (long)m_maintainStraightLines
);
1391 // Make a list of lists for the (sp)line controls
1392 wxExpr
*list
= new wxExpr(wxExprList
);
1393 wxNode
*node
= m_lineControlPoints
->GetFirst();
1396 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
1397 wxExpr
*point_list
= new wxExpr(wxExprList
);
1398 wxExpr
*x_expr
= new wxExpr((double) point
->x
);
1399 wxExpr
*y_expr
= new wxExpr((double) point
->y
);
1400 point_list
->Append(x_expr
);
1401 point_list
->Append(y_expr
);
1402 list
->Append(point_list
);
1404 node
= node
->GetNext();
1406 clause
->AddAttributeValue(_T("controls"), list
);
1408 // Write arc arrows in new OGL format, if there are any.
1409 // This is a list of lists. Each sublist comprises:
1410 // (arrowType arrowEnd xOffset arrowSize)
1411 if (m_arcArrows
.GetCount() > 0)
1413 wxExpr
*arrow_list
= new wxExpr(wxExprList
);
1414 node
= m_arcArrows
.GetFirst();
1417 wxArrowHead
*head
= (wxArrowHead
*)node
->GetData();
1418 wxExpr
*head_list
= new wxExpr(wxExprList
);
1419 head_list
->Append(new wxExpr((long)head
->_GetType()));
1420 head_list
->Append(new wxExpr((long)head
->GetArrowEnd()));
1421 head_list
->Append(new wxExpr(head
->GetXOffset()));
1422 head_list
->Append(new wxExpr(head
->GetArrowSize()));
1423 head_list
->Append(new wxExpr(wxExprString
, head
->GetName()));
1424 head_list
->Append(new wxExpr(head
->GetId()));
1426 // New members of wxArrowHead
1427 head_list
->Append(new wxExpr(head
->GetYOffset()));
1428 head_list
->Append(new wxExpr(head
->GetSpacing()));
1430 arrow_list
->Append(head_list
);
1432 node
= node
->GetNext();
1434 clause
->AddAttributeValue(_T("arrows"), arrow_list
);
1438 void wxLineShape::ReadAttributes(wxExpr
*clause
)
1440 wxShape::ReadAttributes(clause
);
1442 int iVal
= (int) m_isSpline
;
1443 clause
->AssignAttributeValue(wxT("is_spline"), &iVal
);
1444 m_isSpline
= (iVal
!= 0);
1446 iVal
= (int) m_maintainStraightLines
;
1447 clause
->AssignAttributeValue(wxT("keep_lines_straight"), &iVal
);
1448 m_maintainStraightLines
= (iVal
!= 0);
1450 clause
->AssignAttributeValue(wxT("align_start"), &m_alignmentStart
);
1451 clause
->AssignAttributeValue(wxT("align_end"), &m_alignmentEnd
);
1453 // Compatibility: check for no regions.
1454 if (m_regions
.GetCount() == 0)
1456 wxShapeRegion
*newRegion
= new wxShapeRegion
;
1457 newRegion
->SetName(_T("Middle"));
1458 newRegion
->SetSize(150, 50);
1459 m_regions
.Append((wxObject
*)newRegion
);
1460 if (m_text
.GetCount() > 0)
1462 newRegion
->ClearText();
1463 wxNode
*node
= m_text
.GetFirst();
1466 wxShapeTextLine
*textLine
= (wxShapeTextLine
*)node
->GetData();
1467 wxNode
*next
= node
->GetNext();
1468 newRegion
->GetFormattedText().Append((wxObject
*)textLine
);
1474 newRegion
= new wxShapeRegion
;
1475 newRegion
->SetName(wxT("Start"));
1476 newRegion
->SetSize(150, 50);
1477 m_regions
.Append((wxObject
*)newRegion
);
1479 newRegion
= new wxShapeRegion
;
1480 newRegion
->SetName(wxT("End"));
1481 newRegion
->SetSize(150, 50);
1482 m_regions
.Append((wxObject
*)newRegion
);
1486 m_attachmentFrom
= 0;
1488 clause
->AssignAttributeValue(wxT("attachment_to"), &m_attachmentTo
);
1489 clause
->AssignAttributeValue(wxT("attachment_from"), &m_attachmentFrom
);
1491 wxExpr
*line_list
= NULL
;
1493 // When image is created, there are default control points. Override
1494 // them if there are some in the file.
1495 clause
->AssignAttributeValue(wxT("controls"), &line_list
);
1499 // Read a list of lists for the spline controls
1500 if (m_lineControlPoints
)
1502 ClearPointList(*m_lineControlPoints
);
1505 m_lineControlPoints
= new wxList
;
1507 wxExpr
*node
= line_list
->value
.first
;
1511 wxExpr
*xexpr
= node
->value
.first
;
1512 double x
= xexpr
->RealValue();
1514 wxExpr
*yexpr
= xexpr
->next
;
1515 double y
= yexpr
->RealValue();
1517 wxRealPoint
*point
= new wxRealPoint(x
, y
);
1518 m_lineControlPoints
->Append((wxObject
*) point
);
1524 // Read arrow list, for new OGL code
1525 wxExpr
*arrow_list
= NULL
;
1527 clause
->AssignAttributeValue(wxT("arrows"), &arrow_list
);
1530 wxExpr
*node
= arrow_list
->value
.first
;
1534 WXTYPE arrowType
= ARROW_ARROW
;
1536 double xOffset
= 0.0;
1537 double arrowSize
= 0.0;
1541 wxExpr
*type_expr
= node
->Nth(0);
1542 wxExpr
*end_expr
= node
->Nth(1);
1543 wxExpr
*dist_expr
= node
->Nth(2);
1544 wxExpr
*size_expr
= node
->Nth(3);
1545 wxExpr
*name_expr
= node
->Nth(4);
1546 wxExpr
*id_expr
= node
->Nth(5);
1548 // New members of wxArrowHead
1549 wxExpr
*yOffsetExpr
= node
->Nth(6);
1550 wxExpr
*spacingExpr
= node
->Nth(7);
1553 arrowType
= (int)type_expr
->IntegerValue();
1555 arrowEnd
= (int)end_expr
->IntegerValue();
1557 xOffset
= dist_expr
->RealValue();
1559 arrowSize
= size_expr
->RealValue();
1561 arrowName
= name_expr
->StringValue();
1563 arrowId
= id_expr
->IntegerValue();
1566 arrowId
= wxNewId();
1568 wxRegisterId(arrowId
);
1570 wxArrowHead
*arrowHead
= AddArrow(arrowType
, arrowEnd
, arrowSize
, xOffset
, arrowName
, NULL
, arrowId
);
1572 arrowHead
->SetYOffset(yOffsetExpr
->RealValue());
1574 arrowHead
->SetSpacing(spacingExpr
->RealValue());
1582 void wxLineShape::Copy(wxShape
& copy
)
1584 wxShape::Copy(copy
);
1586 wxASSERT( copy
.IsKindOf(CLASSINFO(wxLineShape
)) );
1588 wxLineShape
& lineCopy
= (wxLineShape
&) copy
;
1590 lineCopy
.m_to
= m_to
;
1591 lineCopy
.m_from
= m_from
;
1592 lineCopy
.m_attachmentTo
= m_attachmentTo
;
1593 lineCopy
.m_attachmentFrom
= m_attachmentFrom
;
1594 lineCopy
.m_isSpline
= m_isSpline
;
1595 lineCopy
.m_alignmentStart
= m_alignmentStart
;
1596 lineCopy
.m_alignmentEnd
= m_alignmentEnd
;
1597 lineCopy
.m_maintainStraightLines
= m_maintainStraightLines
;
1598 lineCopy
.m_lineOrientations
.Clear();
1600 wxNode
*node
= m_lineOrientations
.GetFirst();
1603 lineCopy
.m_lineOrientations
.Append(node
->GetData());
1604 node
= node
->GetNext();
1607 if (lineCopy
.m_lineControlPoints
)
1609 ClearPointList(*lineCopy
.m_lineControlPoints
);
1610 delete lineCopy
.m_lineControlPoints
;
1613 lineCopy
.m_lineControlPoints
= new wxList
;
1615 node
= m_lineControlPoints
->GetFirst();
1618 wxRealPoint
*point
= (wxRealPoint
*)node
->GetData();
1619 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
1620 lineCopy
.m_lineControlPoints
->Append((wxObject
*) new_point
);
1621 node
= node
->GetNext();
1625 lineCopy
.ClearArrowsAtPosition(-1);
1626 node
= m_arcArrows
.GetFirst();
1629 wxArrowHead
*arrow
= (wxArrowHead
*)node
->GetData();
1630 lineCopy
.m_arcArrows
.Append(new wxArrowHead(*arrow
));
1631 node
= node
->GetNext();
1635 // Override select, to create/delete temporary label-moving objects
1636 void wxLineShape::Select(bool select
, wxDC
* dc
)
1638 wxShape::Select(select
, dc
);
1641 for (int i
= 0; i
< 3; i
++)
1643 wxNode
*node
= m_regions
.Item(i
);
1646 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
1647 if (region
->m_formattedText
.GetCount() > 0)
1649 double w
, h
, x
, y
, xx
, yy
;
1650 region
->GetSize(&w
, &h
);
1651 region
->GetPosition(&x
, &y
);
1652 GetLabelPosition(i
, &xx
, &yy
);
1653 if (m_labelObjects
[i
])
1655 m_labelObjects
[i
]->Select(FALSE
);
1656 m_labelObjects
[i
]->RemoveFromCanvas(m_canvas
);
1657 delete m_labelObjects
[i
];
1659 m_labelObjects
[i
] = OnCreateLabelShape(this, region
, w
, h
);
1660 m_labelObjects
[i
]->AddToCanvas(m_canvas
);
1661 m_labelObjects
[i
]->Show(TRUE
);
1663 m_labelObjects
[i
]->Move(*dc
, (double)(x
+ xx
), (double)(y
+ yy
));
1664 m_labelObjects
[i
]->Select(TRUE
, dc
);
1671 for (int i
= 0; i
< 3; i
++)
1673 if (m_labelObjects
[i
])
1675 m_labelObjects
[i
]->Select(FALSE
, dc
);
1676 m_labelObjects
[i
]->Erase(*dc
);
1677 m_labelObjects
[i
]->RemoveFromCanvas(m_canvas
);
1678 delete m_labelObjects
[i
];
1679 m_labelObjects
[i
] = NULL
;
1686 * Line control point
1690 IMPLEMENT_DYNAMIC_CLASS(wxLineControlPoint
, wxControlPoint
)
1692 wxLineControlPoint::wxLineControlPoint(wxShapeCanvas
*theCanvas
, wxShape
*object
, double size
, double x
, double y
, int the_type
):
1693 wxControlPoint(theCanvas
, object
, size
, x
, y
, the_type
)
1701 wxLineControlPoint::~wxLineControlPoint()
1705 void wxLineControlPoint::OnDraw(wxDC
& dc
)
1707 wxRectangleShape::OnDraw(dc
);
1710 // Implement movement of Line point
1711 void wxLineControlPoint::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
1713 m_shape
->GetEventHandler()->OnSizingDragLeft(this, draw
, x
, y
, keys
, attachment
);
1716 void wxLineControlPoint::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
1718 m_shape
->GetEventHandler()->OnSizingBeginDragLeft(this, x
, y
, keys
, attachment
);
1721 void wxLineControlPoint::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
1723 m_shape
->GetEventHandler()->OnSizingEndDragLeft(this, x
, y
, keys
, attachment
);
1726 // Control points ('handles') redirect control to the actual shape, to make it easier
1727 // to override sizing behaviour.
1728 void wxLineShape::OnSizingDragLeft(wxControlPoint
* pt
, bool WXUNUSED(draw
), double x
, double y
, int WXUNUSED(keys
), int WXUNUSED(attachment
))
1730 wxLineControlPoint
* lpt
= (wxLineControlPoint
*) pt
;
1732 wxClientDC
dc(GetCanvas());
1733 GetCanvas()->PrepareDC(dc
);
1735 dc
.SetLogicalFunction(OGLRBLF
);
1737 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1738 dc
.SetPen(dottedPen
);
1739 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1741 if (lpt
->m_type
== CONTROL_POINT_LINE
)
1743 m_canvas
->Snap(&x
, &y
);
1745 lpt
->SetX(x
); lpt
->SetY(y
);
1746 lpt
->m_point
->x
= x
; lpt
->m_point
->y
= y
;
1748 wxLineShape
*lineShape
= (wxLineShape
*)this;
1750 wxPen
*old_pen
= lineShape
->GetPen();
1751 wxBrush
*old_brush
= lineShape
->GetBrush();
1753 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1754 lineShape
->SetPen(& dottedPen
);
1755 lineShape
->SetBrush(wxTRANSPARENT_BRUSH
);
1757 lineShape
->GetEventHandler()->OnMoveLink(dc
, FALSE
);
1759 lineShape
->SetPen(old_pen
);
1760 lineShape
->SetBrush(old_brush
);
1763 if (lpt
->m_type
== CONTROL_POINT_ENDPOINT_FROM
|| lpt
->m_type
== CONTROL_POINT_ENDPOINT_TO
)
1765 // lpt->SetX(x); lpt->SetY(y);
1770 void wxLineShape::OnSizingBeginDragLeft(wxControlPoint
* pt
, double x
, double y
, int WXUNUSED(keys
), int WXUNUSED(attachment
))
1772 wxLineControlPoint
* lpt
= (wxLineControlPoint
*) pt
;
1774 wxClientDC
dc(GetCanvas());
1775 GetCanvas()->PrepareDC(dc
);
1777 wxLineShape
*lineShape
= (wxLineShape
*)this;
1778 if (lpt
->m_type
== CONTROL_POINT_LINE
)
1780 lpt
->m_originalPos
= * (lpt
->m_point
);
1781 m_canvas
->Snap(&x
, &y
);
1785 // Redraw start and end objects because we've left holes
1786 // when erasing the line
1787 lineShape
->GetFrom()->OnDraw(dc
);
1788 lineShape
->GetFrom()->OnDrawContents(dc
);
1789 lineShape
->GetTo()->OnDraw(dc
);
1790 lineShape
->GetTo()->OnDrawContents(dc
);
1792 this->SetDisableLabel(TRUE
);
1793 dc
.SetLogicalFunction(OGLRBLF
);
1795 lpt
->m_xpos
= x
; lpt
->m_ypos
= y
;
1796 lpt
->m_point
->x
= x
; lpt
->m_point
->y
= y
;
1798 wxPen
*old_pen
= lineShape
->GetPen();
1799 wxBrush
*old_brush
= lineShape
->GetBrush();
1801 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1802 lineShape
->SetPen(& dottedPen
);
1803 lineShape
->SetBrush(wxTRANSPARENT_BRUSH
);
1805 lineShape
->GetEventHandler()->OnMoveLink(dc
, FALSE
);
1807 lineShape
->SetPen(old_pen
);
1808 lineShape
->SetBrush(old_brush
);
1811 if (lpt
->m_type
== CONTROL_POINT_ENDPOINT_FROM
|| lpt
->m_type
== CONTROL_POINT_ENDPOINT_TO
)
1813 m_canvas
->SetCursor(wxCursor(wxCURSOR_BULLSEYE
));
1814 lpt
->m_oldCursor
= wxSTANDARD_CURSOR
;
1818 void wxLineShape::OnSizingEndDragLeft(wxControlPoint
* pt
, double x
, double y
, int WXUNUSED(keys
), int WXUNUSED(attachment
))
1820 wxLineControlPoint
* lpt
= (wxLineControlPoint
*) pt
;
1822 wxClientDC
dc(GetCanvas());
1823 GetCanvas()->PrepareDC(dc
);
1825 this->SetDisableLabel(FALSE
);
1826 wxLineShape
*lineShape
= (wxLineShape
*)this;
1828 if (lpt
->m_type
== CONTROL_POINT_LINE
)
1830 m_canvas
->Snap(&x
, &y
);
1832 wxRealPoint pt
= wxRealPoint(x
, y
);
1834 // Move the control point back to where it was;
1835 // MoveControlPoint will move it to the new position
1836 // if it decides it wants. We only moved the position
1837 // during user feedback so we could redraw the line
1838 // as it changed shape.
1839 lpt
->m_xpos
= lpt
->m_originalPos
.x
; lpt
->m_ypos
= lpt
->m_originalPos
.y
;
1840 lpt
->m_point
->x
= lpt
->m_originalPos
.x
; lpt
->m_point
->y
= lpt
->m_originalPos
.y
;
1842 OnMoveMiddleControlPoint(dc
, lpt
, pt
);
1844 if (lpt
->m_type
== CONTROL_POINT_ENDPOINT_FROM
)
1846 if (lpt
->m_oldCursor
)
1847 m_canvas
->SetCursor(* lpt
->m_oldCursor
);
1851 // lpt->m_xpos = x; lpt->m_ypos = y;
1853 if (lineShape
->GetFrom())
1855 lineShape
->GetFrom()->MoveLineToNewAttachment(dc
, lineShape
, x
, y
);
1858 if (lpt
->m_type
== CONTROL_POINT_ENDPOINT_TO
)
1860 if (lpt
->m_oldCursor
)
1861 m_canvas
->SetCursor(* lpt
->m_oldCursor
);
1863 // lpt->m_xpos = x; lpt->m_ypos = y;
1865 if (lineShape
->GetTo())
1867 lineShape
->GetTo()->MoveLineToNewAttachment(dc
, lineShape
, x
, y
);
1874 for (i
= 0; i
< lineShape
->GetLineControlPoints()->GetCount(); i
++)
1875 if (((wxRealPoint
*)(lineShape
->GetLineControlPoints()->Item(i
)->GetData())) == lpt
->m_point
)
1878 // N.B. in OnMoveControlPoint, an event handler in Hardy could have deselected
1879 // the line and therefore deleted 'this'. -> GPF, intermittently.
1880 // So assume at this point that we've been blown away.
1882 lineShape
->OnMoveControlPoint(i
+1, x
, y
);
1886 // This is called only when a non-end control point is moved.
1887 bool wxLineShape::OnMoveMiddleControlPoint(wxDC
& dc
, wxLineControlPoint
* lpt
, const wxRealPoint
& pt
)
1889 lpt
->m_xpos
= pt
.x
; lpt
->m_ypos
= pt
.y
;
1890 lpt
->m_point
->x
= pt
.x
; lpt
->m_point
->y
= pt
.y
;
1892 GetEventHandler()->OnMoveLink(dc
);
1897 // Implement movement of endpoint to a new attachment
1898 // OBSOLETE: done by dragging with the left button.
1901 void wxLineControlPoint::OnDragRight(bool draw
, double x
, double y
, int keys
, int attachment
)
1903 if (m_type
== CONTROL_POINT_ENDPOINT_FROM
|| m_type
== CONTROL_POINT_ENDPOINT_TO
)
1905 m_xpos
= x
; m_ypos
= y
;
1909 void wxLineControlPoint::OnBeginDragRight(double x
, double y
, int keys
, int attachment
)
1911 wxClientDC
dc(GetCanvas());
1912 GetCanvas()->PrepareDC(dc
);
1914 wxLineShape
*lineShape
= (wxLineShape
*)m_shape
;
1915 if (m_type
== CONTROL_POINT_ENDPOINT_FROM
|| m_type
== CONTROL_POINT_ENDPOINT_TO
)
1918 lineShape
->GetEventHandler()->OnDraw(dc
);
1919 if (m_type
== CONTROL_POINT_ENDPOINT_FROM
)
1921 lineShape
->GetFrom()->GetEventHandler()->OnDraw(dc
);
1922 lineShape
->GetFrom()->GetEventHandler()->OnDrawContents(dc
);
1926 lineShape
->GetTo()->GetEventHandler()->OnDraw(dc
);
1927 lineShape
->GetTo()->GetEventHandler()->OnDrawContents(dc
);
1929 m_canvas
->SetCursor(wxCursor(wxCURSOR_BULLSEYE
));
1930 m_oldCursor
= wxSTANDARD_CURSOR
;
1934 void wxLineControlPoint::OnEndDragRight(double x
, double y
, int keys
, int attachment
)
1936 wxClientDC
dc(GetCanvas());
1937 GetCanvas()->PrepareDC(dc
);
1939 wxLineShape
*lineShape
= (wxLineShape
*)m_shape
;
1940 if (m_type
== CONTROL_POINT_ENDPOINT_FROM
)
1943 m_canvas
->SetCursor(m_oldCursor
);
1945 m_xpos
= x
; m_ypos
= y
;
1947 if (lineShape
->GetFrom())
1949 lineShape
->GetFrom()->EraseLinks(dc
);
1954 if (lineShape
->GetFrom()->HitTest(x
, y
, &new_attachment
, &distance
))
1955 lineShape
->SetAttachments(new_attachment
, lineShape
->GetAttachmentTo());
1957 lineShape
->GetFrom()->MoveLinks(dc
);
1960 if (m_type
== CONTROL_POINT_ENDPOINT_TO
)
1963 m_canvas
->SetCursor(m_oldCursor
);
1966 m_xpos
= x
; m_ypos
= y
;
1968 if (lineShape
->GetTo())
1970 lineShape
->GetTo()->EraseLinks(dc
);
1974 if (lineShape
->GetTo()->HitTest(x
, y
, &new_attachment
, &distance
))
1975 lineShape
->SetAttachments(lineShape
->GetAttachmentFrom(), new_attachment
);
1977 lineShape
->GetTo()->MoveLinks(dc
);
1981 for (i
= 0; i
< lineShape
->GetLineControlPoints()->GetCount(); i
++)
1982 if (((wxRealPoint
*)(lineShape
->GetLineControlPoints()->Item(i
)->GetData())) == m_point
)
1984 lineShape
->OnMoveControlPoint(i
+1, x
, y
);
1985 if (!m_canvas
->GetQuickEditMode()) m_canvas
->Redraw(dc
);
1990 * Get the point on the given line (x1, y1) (x2, y2)
1991 * distance 'length' along from the end,
1992 * returned values in x and y
1995 void GetPointOnLine(double x1
, double y1
, double x2
, double y2
,
1996 double length
, double *x
, double *y
)
1998 double l
= (double)sqrt((x2
- x1
)*(x2
- x1
) + (y2
- y1
)*(y2
- y1
));
2003 double i_bar
= (x2
- x1
)/l
;
2004 double j_bar
= (y2
- y1
)/l
;
2006 *x
= (- length
*i_bar
) + x2
;
2007 *y
= (- length
*j_bar
) + y2
;
2010 wxArrowHead
*wxLineShape::AddArrow(WXTYPE type
, int end
, double size
, double xOffset
,
2011 const wxString
& name
, wxPseudoMetaFile
*mf
, long arrowId
)
2013 wxArrowHead
*arrow
= new wxArrowHead(type
, end
, size
, xOffset
, name
, mf
, arrowId
);
2014 m_arcArrows
.Append(arrow
);
2019 * Add arrowhead at a particular position in the arrowhead list.
2021 bool wxLineShape::AddArrowOrdered(wxArrowHead
*arrow
, wxList
& referenceList
, int end
)
2023 wxNode
*refNode
= referenceList
.GetFirst();
2024 wxNode
*currNode
= m_arcArrows
.GetFirst();
2025 wxString
targetName(arrow
->GetName());
2026 if (!refNode
) return FALSE
;
2028 // First check whether we need to insert in front of list,
2029 // because this arrowhead is the first in the reference
2030 // list and should therefore be first in the current list.
2031 wxArrowHead
*refArrow
= (wxArrowHead
*)refNode
->GetData();
2032 if (refArrow
->GetName() == targetName
)
2034 m_arcArrows
.Insert(arrow
);
2038 wxArrowHead
*currArrow
= (wxArrowHead
*)currNode
->GetData();
2039 while (refNode
&& currNode
)
2041 refArrow
= (wxArrowHead
*)refNode
->GetData();
2043 // Matching: advance current arrow pointer
2044 if ((currArrow
->GetArrowEnd() == end
) &&
2045 (currArrow
->GetName() == refArrow
->GetName()))
2047 currNode
= currNode
->GetNext(); // Could be NULL now
2049 currArrow
= (wxArrowHead
*)currNode
->GetData();
2052 // Check if we're at the correct position in the
2054 if (targetName
== refArrow
->GetName())
2057 m_arcArrows
.Insert(currNode
, arrow
);
2059 m_arcArrows
.Append(arrow
);
2062 refNode
= refNode
->GetNext();
2064 m_arcArrows
.Append(arrow
);
2068 void wxLineShape::ClearArrowsAtPosition(int end
)
2070 wxNode
*node
= m_arcArrows
.GetFirst();
2073 wxArrowHead
*arrow
= (wxArrowHead
*)node
->GetData();
2074 wxNode
*next
= node
->GetNext();
2083 case ARROW_POSITION_START
:
2085 if (arrow
->GetArrowEnd() == ARROW_POSITION_START
)
2092 case ARROW_POSITION_END
:
2094 if (arrow
->GetArrowEnd() == ARROW_POSITION_END
)
2101 case ARROW_POSITION_MIDDLE
:
2103 if (arrow
->GetArrowEnd() == ARROW_POSITION_MIDDLE
)
2115 bool wxLineShape::ClearArrow(const wxString
& name
)
2117 wxNode
*node
= m_arcArrows
.GetFirst();
2120 wxArrowHead
*arrow
= (wxArrowHead
*)node
->GetData();
2121 if (arrow
->GetName() == name
)
2127 node
= node
->GetNext();
2133 * Finds an arrowhead at the given position (if -1, any position)
2137 wxArrowHead
*wxLineShape::FindArrowHead(int position
, const wxString
& name
)
2139 wxNode
*node
= m_arcArrows
.GetFirst();
2142 wxArrowHead
*arrow
= (wxArrowHead
*)node
->GetData();
2143 if (((position
== -1) || (position
== arrow
->GetArrowEnd())) &&
2144 (arrow
->GetName() == name
))
2146 node
= node
->GetNext();
2151 wxArrowHead
*wxLineShape::FindArrowHead(long arrowId
)
2153 wxNode
*node
= m_arcArrows
.GetFirst();
2156 wxArrowHead
*arrow
= (wxArrowHead
*)node
->GetData();
2157 if (arrowId
== arrow
->GetId())
2159 node
= node
->GetNext();
2165 * Deletes an arrowhead at the given position (if -1, any position)
2169 bool wxLineShape::DeleteArrowHead(int position
, const wxString
& name
)
2171 wxNode
*node
= m_arcArrows
.GetFirst();
2174 wxArrowHead
*arrow
= (wxArrowHead
*)node
->GetData();
2175 if (((position
== -1) || (position
== arrow
->GetArrowEnd())) &&
2176 (arrow
->GetName() == name
))
2182 node
= node
->GetNext();
2187 // Overloaded DeleteArrowHead: pass arrowhead id.
2188 bool wxLineShape::DeleteArrowHead(long id
)
2190 wxNode
*node
= m_arcArrows
.GetFirst();
2193 wxArrowHead
*arrow
= (wxArrowHead
*)node
->GetData();
2194 if (arrow
->GetId() == id
)
2200 node
= node
->GetNext();
2206 * Calculate the minimum width a line
2207 * occupies, for the purposes of drawing lines in tools.
2211 double wxLineShape::FindMinimumWidth()
2213 double minWidth
= 0.0;
2214 wxNode
*node
= m_arcArrows
.GetFirst();
2217 wxArrowHead
*arrowHead
= (wxArrowHead
*)node
->GetData();
2218 minWidth
+= arrowHead
->GetSize();
2219 if (node
->GetNext())
2220 minWidth
+= arrowHead
->GetSpacing();
2222 node
= node
->GetNext();
2224 // We have ABSOLUTE minimum now. So
2225 // scale it to give it reasonable aesthetics
2226 // when drawing with line.
2228 minWidth
= (double)(minWidth
* 1.4);
2232 SetEnds(0.0, 0.0, minWidth
, 0.0);
2238 // Find which position we're talking about at this (x, y).
2239 // Returns ARROW_POSITION_START, ARROW_POSITION_MIDDLE, ARROW_POSITION_END
2240 int wxLineShape::FindLinePosition(double x
, double y
)
2242 double startX
, startY
, endX
, endY
;
2243 GetEnds(&startX
, &startY
, &endX
, &endY
);
2245 // Find distances from centre, start and end. The smallest wins.
2246 double centreDistance
= (double)(sqrt((x
- m_xpos
)*(x
- m_xpos
) + (y
- m_ypos
)*(y
- m_ypos
)));
2247 double startDistance
= (double)(sqrt((x
- startX
)*(x
- startX
) + (y
- startY
)*(y
- startY
)));
2248 double endDistance
= (double)(sqrt((x
- endX
)*(x
- endX
) + (y
- endY
)*(y
- endY
)));
2250 if (centreDistance
< startDistance
&& centreDistance
< endDistance
)
2251 return ARROW_POSITION_MIDDLE
;
2252 else if (startDistance
< endDistance
)
2253 return ARROW_POSITION_START
;
2255 return ARROW_POSITION_END
;
2258 // Set alignment flags
2259 void wxLineShape::SetAlignmentOrientation(bool isEnd
, bool isHoriz
)
2263 if (isHoriz
&& ((m_alignmentEnd
& LINE_ALIGNMENT_HORIZ
) != LINE_ALIGNMENT_HORIZ
))
2264 m_alignmentEnd
|= LINE_ALIGNMENT_HORIZ
;
2265 else if (!isHoriz
&& ((m_alignmentEnd
& LINE_ALIGNMENT_HORIZ
) == LINE_ALIGNMENT_HORIZ
))
2266 m_alignmentEnd
-= LINE_ALIGNMENT_HORIZ
;
2270 if (isHoriz
&& ((m_alignmentStart
& LINE_ALIGNMENT_HORIZ
) != LINE_ALIGNMENT_HORIZ
))
2271 m_alignmentStart
|= LINE_ALIGNMENT_HORIZ
;
2272 else if (!isHoriz
&& ((m_alignmentStart
& LINE_ALIGNMENT_HORIZ
) == LINE_ALIGNMENT_HORIZ
))
2273 m_alignmentStart
-= LINE_ALIGNMENT_HORIZ
;
2277 void wxLineShape::SetAlignmentType(bool isEnd
, int alignType
)
2281 if (alignType
== LINE_ALIGNMENT_TO_NEXT_HANDLE
)
2283 if ((m_alignmentEnd
& LINE_ALIGNMENT_TO_NEXT_HANDLE
) != LINE_ALIGNMENT_TO_NEXT_HANDLE
)
2284 m_alignmentEnd
|= LINE_ALIGNMENT_TO_NEXT_HANDLE
;
2286 else if ((m_alignmentEnd
& LINE_ALIGNMENT_TO_NEXT_HANDLE
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
)
2287 m_alignmentEnd
-= LINE_ALIGNMENT_TO_NEXT_HANDLE
;
2291 if (alignType
== LINE_ALIGNMENT_TO_NEXT_HANDLE
)
2293 if ((m_alignmentStart
& LINE_ALIGNMENT_TO_NEXT_HANDLE
) != LINE_ALIGNMENT_TO_NEXT_HANDLE
)
2294 m_alignmentStart
|= LINE_ALIGNMENT_TO_NEXT_HANDLE
;
2296 else if ((m_alignmentStart
& LINE_ALIGNMENT_TO_NEXT_HANDLE
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
)
2297 m_alignmentStart
-= LINE_ALIGNMENT_TO_NEXT_HANDLE
;
2301 bool wxLineShape::GetAlignmentOrientation(bool isEnd
)
2304 return ((m_alignmentEnd
& LINE_ALIGNMENT_HORIZ
) == LINE_ALIGNMENT_HORIZ
);
2306 return ((m_alignmentStart
& LINE_ALIGNMENT_HORIZ
) == LINE_ALIGNMENT_HORIZ
);
2309 int wxLineShape::GetAlignmentType(bool isEnd
)
2312 return (m_alignmentEnd
& LINE_ALIGNMENT_TO_NEXT_HANDLE
);
2314 return (m_alignmentStart
& LINE_ALIGNMENT_TO_NEXT_HANDLE
);
2317 wxRealPoint
*wxLineShape::GetNextControlPoint(wxShape
*nodeObject
)
2319 int n
= m_lineControlPoints
->GetCount();
2321 if (m_to
== nodeObject
)
2323 // Must be END of line, so we want (n - 1)th control point.
2324 // But indexing ends at n-1, so subtract 2.
2328 wxNode
*node
= m_lineControlPoints
->Item(nn
);
2331 return (wxRealPoint
*)node
->GetData();
2342 IMPLEMENT_DYNAMIC_CLASS(wxArrowHead
, wxObject
)
2344 wxArrowHead::wxArrowHead(WXTYPE type
, int end
, double size
, double dist
, const wxString
& name
,
2345 wxPseudoMetaFile
*mf
, long arrowId
)
2347 m_arrowType
= type
; m_arrowEnd
= end
; m_arrowSize
= size
;
2359 wxArrowHead::wxArrowHead(wxArrowHead
& toCopy
)
2361 m_arrowType
= toCopy
.m_arrowType
; m_arrowEnd
= toCopy
.GetArrowEnd();
2362 m_arrowSize
= toCopy
.m_arrowSize
;
2363 m_xOffset
= toCopy
.m_xOffset
;
2364 m_yOffset
= toCopy
.m_yOffset
;
2365 m_spacing
= toCopy
.m_spacing
;
2366 m_arrowName
= toCopy
.m_arrowName
;
2367 if (toCopy
.m_metaFile
)
2368 m_metaFile
= new wxPseudoMetaFile(*(toCopy
.m_metaFile
));
2374 wxArrowHead::~wxArrowHead()
2376 if (m_metaFile
) delete m_metaFile
;
2379 void wxArrowHead::SetSize(double size
)
2382 if ((m_arrowType
== ARROW_METAFILE
) && m_metaFile
)
2384 double oldWidth
= m_metaFile
->m_width
;
2385 if (oldWidth
== 0.0)
2388 double scale
= (double)(size
/oldWidth
);
2390 m_metaFile
->Scale(scale
, scale
);
2394 // Can override this to create a different class of label shape
2395 wxLabelShape
* wxLineShape::OnCreateLabelShape(wxLineShape
*parent
, wxShapeRegion
*region
, double w
, double h
)
2397 return new wxLabelShape(parent
, region
, w
, h
);
2405 IMPLEMENT_DYNAMIC_CLASS(wxLabelShape
, wxRectangleShape
)
2407 wxLabelShape::wxLabelShape(wxLineShape
*parent
, wxShapeRegion
*region
, double w
, double h
):wxRectangleShape(w
, h
)
2409 m_lineShape
= parent
;
2410 m_shapeRegion
= region
;
2411 SetPen(wxThePenList
->FindOrCreatePen(wxColour(0, 0, 0), 1, wxDOT
));
2414 wxLabelShape::~wxLabelShape()
2418 void wxLabelShape::OnDraw(wxDC
& dc
)
2420 if (m_lineShape
&& !m_lineShape
->GetDrawHandles())
2423 double x1
= (double)(m_xpos
- m_width
/2.0);
2424 double y1
= (double)(m_ypos
- m_height
/2.0);
2428 if (m_pen
->GetWidth() == 0)
2429 dc
.SetPen(* g_oglTransparentPen
);
2433 dc
.SetBrush(* wxTRANSPARENT_BRUSH
);
2435 if (m_cornerRadius
> 0.0)
2436 dc
.DrawRoundedRectangle(WXROUND(x1
), WXROUND(y1
), WXROUND(m_width
), WXROUND(m_height
), m_cornerRadius
);
2438 dc
.DrawRectangle(WXROUND(x1
), WXROUND(y1
), WXROUND(m_width
), WXROUND(m_height
));
2441 void wxLabelShape::OnDrawContents(wxDC
& WXUNUSED(dc
))
2445 void wxLabelShape::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
2447 wxRectangleShape::OnDragLeft(draw
, x
, y
, keys
, attachment
);
2450 void wxLabelShape::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
2452 wxRectangleShape::OnBeginDragLeft(x
, y
, keys
, attachment
);
2455 void wxLabelShape::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
2457 wxRectangleShape::OnEndDragLeft(x
, y
, keys
, attachment
);
2460 bool wxLabelShape::OnMovePre(wxDC
& dc
, double x
, double y
, double old_x
, double old_y
, bool display
)
2462 return m_lineShape
->OnLabelMovePre(dc
, this, x
, y
, old_x
, old_y
, display
);
2465 bool wxLineShape::OnLabelMovePre(wxDC
& dc
, wxLabelShape
* labelShape
, double x
, double y
, double WXUNUSED(old_x
), double WXUNUSED(old_y
), bool WXUNUSED(display
))
2467 labelShape
->m_shapeRegion
->SetSize(labelShape
->GetWidth(), labelShape
->GetHeight());
2469 // Find position in line's region list
2471 wxNode
*node
= GetRegions().GetFirst();
2474 if (labelShape
->m_shapeRegion
== (wxShapeRegion
*)node
->GetData())
2478 node
= node
->GetNext();
2483 GetLabelPosition(i
, &xx
, &yy
);
2484 // Set the region's offset, relative to the default position for
2486 labelShape
->m_shapeRegion
->SetPosition((double)(x
- xx
), (double)(y
- yy
));
2488 labelShape
->SetX(x
);
2489 labelShape
->SetY(y
);
2491 // Need to reformat to fit region.
2492 if (labelShape
->m_shapeRegion
->GetText())
2495 wxString
s(labelShape
->m_shapeRegion
->GetText());
2496 labelShape
->FormatText(dc
, s
, i
);
2497 DrawRegion(dc
, labelShape
->m_shapeRegion
, xx
, yy
);
2502 // Divert left and right clicks to line object
2503 void wxLabelShape::OnLeftClick(double x
, double y
, int keys
, int attachment
)
2505 m_lineShape
->GetEventHandler()->OnLeftClick(x
, y
, keys
, attachment
);
2508 void wxLabelShape::OnRightClick(double x
, double y
, int keys
, int attachment
)
2510 m_lineShape
->GetEventHandler()->OnRightClick(x
, y
, keys
, attachment
);