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"
28 #include <wx/wxexpr.h>
43 #include <wx/ogl/basic.h>
44 #include <wx/ogl/basicp.h>
45 #include <wx/ogl/lines.h>
46 #include <wx/ogl/linesp.h>
47 #include <wx/ogl/drawn.h>
48 #include <wx/ogl/misc.h>
49 #include <wx/ogl/canvas.h>
52 IMPLEMENT_DYNAMIC_CLASS(wxLineShape
, wxShape
)
54 wxLineShape::wxLineShape()
56 m_sensitivity
= OP_CLICK_LEFT
| OP_CLICK_RIGHT
;
61 m_actualTextWidth = 0.0;
62 m_actualTextHeight = 0.0;
67 m_arrowSpacing
= 5.0; // For the moment, don't bother saving this to file.
68 m_ignoreArrowOffsets
= FALSE
;
70 m_maintainStraightLines
= FALSE
;
74 m_lineControlPoints
= NULL
;
76 // Clear any existing regions (created in an earlier constructor)
77 // and make the three line regions.
79 wxShapeRegion
*newRegion
= new wxShapeRegion
;
80 newRegion
->SetName(wxT("Middle"));
81 newRegion
->SetSize(150, 50);
82 m_regions
.Append((wxObject
*)newRegion
);
84 newRegion
= new wxShapeRegion
;
85 newRegion
->SetName(wxT("Start"));
86 newRegion
->SetSize(150, 50);
87 m_regions
.Append((wxObject
*)newRegion
);
89 newRegion
= new wxShapeRegion
;
90 newRegion
->SetName(wxT("End"));
91 newRegion
->SetSize(150, 50);
92 m_regions
.Append((wxObject
*)newRegion
);
94 for (int i
= 0; i
< 3; i
++)
95 m_labelObjects
[i
] = NULL
;
98 wxLineShape::~wxLineShape()
100 if (m_lineControlPoints
)
102 ClearPointList(*m_lineControlPoints
);
103 delete m_lineControlPoints
;
105 for (int i
= 0; i
< 3; i
++)
107 if (m_labelObjects
[i
])
109 m_labelObjects
[i
]->Select(FALSE
);
110 m_labelObjects
[i
]->RemoveFromCanvas(m_canvas
);
111 delete m_labelObjects
[i
];
112 m_labelObjects
[i
] = NULL
;
115 ClearArrowsAtPosition(-1);
118 void wxLineShape::MakeLineControlPoints(int n
)
120 if (m_lineControlPoints
)
122 ClearPointList(*m_lineControlPoints
);
123 delete m_lineControlPoints
;
125 m_lineControlPoints
= new wxList
;
128 for (i
= 0; i
< n
; i
++)
130 wxRealPoint
*point
= new wxRealPoint(-999, -999);
131 m_lineControlPoints
->Append((wxObject
*) point
);
135 wxNode
*wxLineShape::InsertLineControlPoint(wxDC
* dc
)
140 wxNode
*last
= m_lineControlPoints
->Last();
141 wxNode
*second_last
= last
->Previous();
142 wxRealPoint
*last_point
= (wxRealPoint
*)last
->Data();
143 wxRealPoint
*second_last_point
= (wxRealPoint
*)second_last
->Data();
145 // Choose a point half way between the last and penultimate points
146 double line_x
= ((last_point
->x
+ second_last_point
->x
)/2);
147 double line_y
= ((last_point
->y
+ second_last_point
->y
)/2);
149 wxRealPoint
*point
= new wxRealPoint(line_x
, line_y
);
150 wxNode
*node
= m_lineControlPoints
->Insert(last
, (wxObject
*) point
);
154 bool wxLineShape::DeleteLineControlPoint()
156 if (m_lineControlPoints
->Number() < 3)
159 wxNode
*last
= m_lineControlPoints
->Last();
160 wxNode
*second_last
= last
->Previous();
162 wxRealPoint
*second_last_point
= (wxRealPoint
*)second_last
->Data();
163 delete second_last_point
;
169 void wxLineShape::Initialise()
171 if (m_lineControlPoints
)
173 // Just move the first and last control points
174 wxNode
*first
= m_lineControlPoints
->First();
175 wxRealPoint
*first_point
= (wxRealPoint
*)first
->Data();
177 wxNode
*last
= m_lineControlPoints
->Last();
178 wxRealPoint
*last_point
= (wxRealPoint
*)last
->Data();
180 // If any of the line points are at -999, we must
181 // initialize them by placing them half way between the first
183 wxNode
*node
= first
->Next();
186 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
187 if (point
->x
== -999)
189 double x1
, y1
, x2
, y2
;
190 if (first_point
->x
< last_point
->x
)
191 { x1
= first_point
->x
; x2
= last_point
->x
; }
193 { x2
= first_point
->x
; x1
= last_point
->x
; }
195 if (first_point
->y
< last_point
->y
)
196 { y1
= first_point
->y
; y2
= last_point
->y
; }
198 { y2
= first_point
->y
; y1
= last_point
->y
; }
200 point
->x
= ((x2
- x1
)/2 + x1
);
201 point
->y
= ((y2
- y1
)/2 + y1
);
208 // Format a text string according to the region size, adding
209 // strings with positions to region text list
210 void wxLineShape::FormatText(wxDC
& dc
, const wxString
& s
, int i
)
215 if (m_regions
.Number() < 1)
217 wxNode
*node
= m_regions
.Nth(i
);
221 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
223 dc
.SetFont(* region
->GetFont());
225 region
->GetSize(&w
, &h
);
226 // Initialize the size if zero
227 if (((w
== 0) || (h
== 0)) && (s
.Length() > 0))
230 region
->SetSize(w
, h
);
233 wxStringList
*string_list
= oglFormatText(dc
, s
, (w
-5), (h
-5), region
->GetFormatMode());
234 node
= string_list
->First();
237 wxChar
*s
= (wxChar
*)node
->Data();
238 wxShapeTextLine
*line
= new wxShapeTextLine(0.0, 0.0, s
);
239 region
->GetFormattedText().Append((wxObject
*)line
);
245 if (region
->GetFormatMode() & FORMAT_SIZE_TO_CONTENTS
)
247 oglGetCentredTextExtent(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, w
, h
, &actualW
, &actualH
);
248 if ((actualW
!= w
) || (actualH
!= h
))
251 GetLabelPosition(i
, &xx
, &yy
);
252 EraseRegion(dc
, region
, xx
, yy
);
253 if (m_labelObjects
[i
])
255 m_labelObjects
[i
]->Select(FALSE
, &dc
);
256 m_labelObjects
[i
]->Erase(dc
);
257 m_labelObjects
[i
]->SetSize(actualW
, actualH
);
260 region
->SetSize(actualW
, actualH
);
262 if (m_labelObjects
[i
])
264 m_labelObjects
[i
]->Select(TRUE
, & dc
);
265 m_labelObjects
[i
]->Draw(dc
);
269 oglCentreText(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, actualW
, actualH
, region
->GetFormatMode());
273 void wxLineShape::DrawRegion(wxDC
& dc
, wxShapeRegion
*region
, double x
, double y
)
275 if (GetDisableLabel())
280 region
->GetSize(&w
, &h
);
282 // Get offset from x, y
283 region
->GetPosition(&xx
, &yy
);
288 // First, clear a rectangle for the text IF there is any
289 if (region
->GetFormattedText().Number() > 0)
291 dc
.SetPen(GetBackgroundPen());
292 dc
.SetBrush(GetBackgroundBrush());
295 if (region
->GetFont()) dc
.SetFont(* region
->GetFont());
297 dc
.DrawRectangle((long)(xp
- w
/2.0), (long)(yp
- h
/2.0), (long)w
, (long)h
);
299 if (m_pen
) dc
.SetPen(* m_pen
);
300 dc
.SetTextForeground(* region
->GetActualColourObject());
303 dc
.SetTextBackground(GetBackgroundBrush().GetColour());
306 oglDrawFormattedText(dc
, &(region
->GetFormattedText()), xp
, yp
, w
, h
, region
->GetFormatMode());
310 void wxLineShape::EraseRegion(wxDC
& dc
, wxShapeRegion
*region
, double x
, double y
)
312 if (GetDisableLabel())
317 region
->GetSize(&w
, &h
);
319 // Get offset from x, y
320 region
->GetPosition(&xx
, &yy
);
325 if (region
->GetFormattedText().Number() > 0)
327 dc
.SetPen(GetBackgroundPen());
328 dc
.SetBrush(GetBackgroundBrush());
330 dc
.DrawRectangle((long)(xp
- w
/2.0), (long)(yp
- h
/2.0), (long)w
, (long)h
);
334 // Get the reference point for a label. Region x and y
335 // are offsets from this.
336 // position is 0, 1, 2
337 void wxLineShape::GetLabelPosition(int position
, double *x
, double *y
)
343 // Want to take the middle section for the label
344 int n
= m_lineControlPoints
->Number();
345 int half_way
= (int)(n
/2);
347 // Find middle of this line
348 wxNode
*node
= m_lineControlPoints
->Nth(half_way
- 1);
349 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
350 wxNode
*next_node
= node
->Next();
351 wxRealPoint
*next_point
= (wxRealPoint
*)next_node
->Data();
353 double dx
= (next_point
->x
- point
->x
);
354 double dy
= (next_point
->y
- point
->y
);
355 *x
= (double)(point
->x
+ dx
/2.0);
356 *y
= (double)(point
->y
+ dy
/2.0);
361 wxNode
*node
= m_lineControlPoints
->First();
362 *x
= ((wxRealPoint
*)node
->Data())->x
;
363 *y
= ((wxRealPoint
*)node
->Data())->y
;
368 wxNode
*node
= m_lineControlPoints
->Last();
369 *x
= ((wxRealPoint
*)node
->Data())->x
;
370 *y
= ((wxRealPoint
*)node
->Data())->y
;
379 * Find whether line is supposed to be vertical or horizontal and
383 void GraphicsStraightenLine(wxRealPoint
*point1
, wxRealPoint
*point2
)
385 double dx
= point2
->x
- point1
->x
;
386 double dy
= point2
->y
- point1
->y
;
390 else if (fabs(dy
/dx
) > 1.0)
392 point2
->x
= point1
->x
;
394 else point2
->y
= point1
->y
;
397 void wxLineShape::Straighten(wxDC
*dc
)
399 if (!m_lineControlPoints
|| m_lineControlPoints
->Number() < 3)
405 wxNode
*first_point_node
= m_lineControlPoints
->First();
406 wxNode
*last_point_node
= m_lineControlPoints
->Last();
407 wxNode
*second_last_point_node
= last_point_node
->Previous();
409 wxRealPoint
*last_point
= (wxRealPoint
*)last_point_node
->Data();
410 wxRealPoint
*second_last_point
= (wxRealPoint
*)second_last_point_node
->Data();
412 GraphicsStraightenLine(last_point
, second_last_point
);
414 wxNode
*node
= first_point_node
;
415 while (node
&& (node
!= second_last_point_node
))
417 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
418 wxRealPoint
*next_point
= (wxRealPoint
*)(node
->Next()->Data());
420 GraphicsStraightenLine(point
, next_point
);
429 void wxLineShape::Unlink()
432 m_to
->GetLines().DeleteObject(this);
434 m_from
->GetLines().DeleteObject(this);
439 void wxLineShape::SetEnds(double x1
, double y1
, double x2
, double y2
)
442 wxNode
*first_point_node
= m_lineControlPoints
->First();
443 wxNode
*last_point_node
= m_lineControlPoints
->Last();
444 wxRealPoint
*first_point
= (wxRealPoint
*)first_point_node
->Data();
445 wxRealPoint
*last_point
= (wxRealPoint
*)last_point_node
->Data();
452 m_xpos
= (double)((x1
+ x2
)/2.0);
453 m_ypos
= (double)((y1
+ y2
)/2.0);
456 // Get absolute positions of ends
457 void wxLineShape::GetEnds(double *x1
, double *y1
, double *x2
, double *y2
)
459 wxNode
*first_point_node
= m_lineControlPoints
->First();
460 wxNode
*last_point_node
= m_lineControlPoints
->Last();
461 wxRealPoint
*first_point
= (wxRealPoint
*)first_point_node
->Data();
462 wxRealPoint
*last_point
= (wxRealPoint
*)last_point_node
->Data();
464 *x1
= first_point
->x
; *y1
= first_point
->y
;
465 *x2
= last_point
->x
; *y2
= last_point
->y
;
468 void wxLineShape::SetAttachments(int from_attach
, int to_attach
)
470 m_attachmentFrom
= from_attach
;
471 m_attachmentTo
= to_attach
;
474 bool wxLineShape::HitTest(double x
, double y
, int *attachment
, double *distance
)
476 if (!m_lineControlPoints
)
479 // Look at label regions in case mouse is over a label
480 bool inLabelRegion
= FALSE
;
481 for (int i
= 0; i
< 3; i
++)
483 wxNode
*regionNode
= m_regions
.Nth(i
);
486 wxShapeRegion
*region
= (wxShapeRegion
*)regionNode
->Data();
487 if (region
->m_formattedText
.Number() > 0)
489 double xp
, yp
, cx
, cy
, cw
, ch
;
490 GetLabelPosition(i
, &xp
, &yp
);
491 // Offset region from default label position
492 region
->GetPosition(&cx
, &cy
);
493 region
->GetSize(&cw
, &ch
);
496 double rLeft
= (double)(cx
- (cw
/2.0));
497 double rTop
= (double)(cy
- (ch
/2.0));
498 double rRight
= (double)(cx
+ (cw
/2.0));
499 double rBottom
= (double)(cy
+ (ch
/2.0));
500 if (x
> rLeft
&& x
< rRight
&& y
> rTop
&& y
< rBottom
)
502 inLabelRegion
= TRUE
;
509 wxNode
*node
= m_lineControlPoints
->First();
511 while (node
&& node
->Next())
513 wxRealPoint
*point1
= (wxRealPoint
*)node
->Data();
514 wxRealPoint
*point2
= (wxRealPoint
*)node
->Next()->Data();
516 // Allow for inaccurate mousing or vert/horiz lines
518 double left
= wxMin(point1
->x
, point2
->x
) - extra
;
519 double right
= wxMax(point1
->x
, point2
->x
) + extra
;
521 double bottom
= wxMin(point1
->y
, point2
->y
) - extra
;
522 double top
= wxMax(point1
->y
, point2
->y
) + extra
;
524 if ((x
> left
&& x
< right
&& y
> bottom
&& y
< top
) || inLabelRegion
)
526 // Work out distance from centre of line
527 double centre_x
= (double)(left
+ (right
- left
)/2.0);
528 double centre_y
= (double)(bottom
+ (top
- bottom
)/2.0);
531 *distance
= (double)sqrt((centre_x
- x
)*(centre_x
- x
) + (centre_y
- y
)*(centre_y
- y
));
540 void wxLineShape::DrawArrows(wxDC
& dc
)
542 // Distance along line of each arrow: space them out evenly.
543 double startArrowPos
= 0.0;
544 double endArrowPos
= 0.0;
545 double middleArrowPos
= 0.0;
547 wxNode
*node
= m_arcArrows
.First();
550 wxArrowHead
*arrow
= (wxArrowHead
*)node
->Data();
551 switch (arrow
->GetArrowEnd())
553 case ARROW_POSITION_START
:
555 if ((arrow
->GetXOffset() != 0.0) && !m_ignoreArrowOffsets
)
556 // If specified, x offset is proportional to line length
557 DrawArrow(dc
, arrow
, arrow
->GetXOffset(), TRUE
);
560 DrawArrow(dc
, arrow
, startArrowPos
, FALSE
); // Absolute distance
561 startArrowPos
+= arrow
->GetSize() + arrow
->GetSpacing();
565 case ARROW_POSITION_END
:
567 if ((arrow
->GetXOffset() != 0.0) && !m_ignoreArrowOffsets
)
568 DrawArrow(dc
, arrow
, arrow
->GetXOffset(), TRUE
);
571 DrawArrow(dc
, arrow
, endArrowPos
, FALSE
);
572 endArrowPos
+= arrow
->GetSize() + arrow
->GetSpacing();
576 case ARROW_POSITION_MIDDLE
:
578 arrow
->SetXOffset(middleArrowPos
);
579 if ((arrow
->GetXOffset() != 0.0) && !m_ignoreArrowOffsets
)
580 DrawArrow(dc
, arrow
, arrow
->GetXOffset(), TRUE
);
583 DrawArrow(dc
, arrow
, middleArrowPos
, FALSE
);
584 middleArrowPos
+= arrow
->GetSize() + arrow
->GetSpacing();
593 void wxLineShape::DrawArrow(wxDC
& dc
, wxArrowHead
*arrow
, double xOffset
, bool proportionalOffset
)
595 wxNode
*first_line_node
= m_lineControlPoints
->First();
596 wxRealPoint
*first_line_point
= (wxRealPoint
*)first_line_node
->Data();
597 wxNode
*second_line_node
= first_line_node
->Next();
598 wxRealPoint
*second_line_point
= (wxRealPoint
*)second_line_node
->Data();
600 wxNode
*last_line_node
= m_lineControlPoints
->Last();
601 wxRealPoint
*last_line_point
= (wxRealPoint
*)last_line_node
->Data();
602 wxNode
*second_last_line_node
= last_line_node
->Previous();
603 wxRealPoint
*second_last_line_point
= (wxRealPoint
*)second_last_line_node
->Data();
605 // Position where we want to start drawing
606 double positionOnLineX
, positionOnLineY
;
608 // Position of start point of line, at the end of which we draw the arrow.
609 double startPositionX
, startPositionY
;
611 switch (arrow
->GetPosition())
613 case ARROW_POSITION_START
:
615 // If we're using a proportional offset, calculate just where this will
617 double realOffset
= xOffset
;
618 if (proportionalOffset
)
621 (double)sqrt((second_line_point
->x
- first_line_point
->x
)*(second_line_point
->x
- first_line_point
->x
) +
622 (second_line_point
->y
- first_line_point
->y
)*(second_line_point
->y
- first_line_point
->y
));
623 realOffset
= (double)(xOffset
* totalLength
);
625 GetPointOnLine(second_line_point
->x
, second_line_point
->y
,
626 first_line_point
->x
, first_line_point
->y
,
627 realOffset
, &positionOnLineX
, &positionOnLineY
);
628 startPositionX
= second_line_point
->x
;
629 startPositionY
= second_line_point
->y
;
632 case ARROW_POSITION_END
:
634 // If we're using a proportional offset, calculate just where this will
636 double realOffset
= xOffset
;
637 if (proportionalOffset
)
640 (double)sqrt((second_last_line_point
->x
- last_line_point
->x
)*(second_last_line_point
->x
- last_line_point
->x
) +
641 (second_last_line_point
->y
- last_line_point
->y
)*(second_last_line_point
->y
- last_line_point
->y
));
642 realOffset
= (double)(xOffset
* totalLength
);
644 GetPointOnLine(second_last_line_point
->x
, second_last_line_point
->y
,
645 last_line_point
->x
, last_line_point
->y
,
646 realOffset
, &positionOnLineX
, &positionOnLineY
);
647 startPositionX
= second_last_line_point
->x
;
648 startPositionY
= second_last_line_point
->y
;
651 case ARROW_POSITION_MIDDLE
:
653 // Choose a point half way between the last and penultimate points
654 double x
= ((last_line_point
->x
+ second_last_line_point
->x
)/2);
655 double y
= ((last_line_point
->y
+ second_last_line_point
->y
)/2);
657 // If we're using a proportional offset, calculate just where this will
659 double realOffset
= xOffset
;
660 if (proportionalOffset
)
663 (double)sqrt((second_last_line_point
->x
- x
)*(second_last_line_point
->x
- x
) +
664 (second_last_line_point
->y
- y
)*(second_last_line_point
->y
- y
));
665 realOffset
= (double)(xOffset
* totalLength
);
668 GetPointOnLine(second_last_line_point
->x
, second_last_line_point
->y
,
669 x
, y
, realOffset
, &positionOnLineX
, &positionOnLineY
);
670 startPositionX
= second_last_line_point
->x
;
671 startPositionY
= second_last_line_point
->y
;
677 * Add yOffset to arrow, if any
680 const double myPi
= (double) 3.14159265;
681 // The translation that the y offset may give
684 if ((arrow
->GetYOffset() != 0.0) && !m_ignoreArrowOffsets
)
690 (x1, y1)--------------(x3, y3)------------------(x2, y2)
691 x4 = x3 - d * sin(theta)
692 y4 = y3 + d * cos(theta)
694 Where theta = tan(-1) of (y3-y1)/(x3-x1)
696 double x1
= startPositionX
;
697 double y1
= startPositionY
;
698 double x3
= positionOnLineX
;
699 double y3
= positionOnLineY
;
700 double d
= -arrow
->GetYOffset(); // Negate so +offset is above line
704 theta
= (double)(myPi
/2.0);
706 theta
= (double)atan((y3
-y1
)/(x3
-x1
));
708 double x4
= (double)(x3
- (d
*sin(theta
)));
709 double y4
= (double)(y3
+ (d
*cos(theta
)));
711 deltaX
= x4
- positionOnLineX
;
712 deltaY
= y4
- positionOnLineY
;
715 switch (arrow
->_GetType())
719 double arrowLength
= arrow
->GetSize();
720 double arrowWidth
= (double)(arrowLength
/3.0);
722 double tip_x
, tip_y
, side1_x
, side1_y
, side2_x
, side2_y
;
723 oglGetArrowPoints(startPositionX
+deltaX
, startPositionY
+deltaY
,
724 positionOnLineX
+deltaX
, positionOnLineY
+deltaY
,
725 arrowLength
, arrowWidth
, &tip_x
, &tip_y
,
726 &side1_x
, &side1_y
, &side2_x
, &side2_y
);
729 points
[0].x
= (int) tip_x
; points
[0].y
= (int) tip_y
;
730 points
[1].x
= (int) side1_x
; points
[1].y
= (int) side1_y
;
731 points
[2].x
= (int) side2_x
; points
[2].y
= (int) side2_y
;
732 points
[3].x
= (int) tip_x
; points
[3].y
= (int) tip_y
;
735 dc
.SetBrush(* m_brush
);
736 dc
.DrawPolygon(4, points
);
739 case ARROW_HOLLOW_CIRCLE
:
740 case ARROW_FILLED_CIRCLE
:
742 // Find point on line of centre of circle, which is a radius away
743 // from the end position
744 double diameter
= (double)(arrow
->GetSize());
746 GetPointOnLine(startPositionX
+deltaX
, startPositionY
+deltaY
,
747 positionOnLineX
+deltaX
, positionOnLineY
+deltaY
,
748 (double)(diameter
/2.0),
751 // Convert ellipse centre to top-left coordinates
752 double x1
= (double)(x
- (diameter
/2.0));
753 double y1
= (double)(y
- (diameter
/2.0));
756 if (arrow
->_GetType() == ARROW_HOLLOW_CIRCLE
)
757 dc
.SetBrush(* g_oglWhiteBackgroundBrush
);
759 dc
.SetBrush(* m_brush
);
761 dc
.DrawEllipse((long) x1
, (long) y1
, (long) diameter
, (long) diameter
);
764 case ARROW_SINGLE_OBLIQUE
:
770 if (arrow
->GetMetaFile())
772 // Find point on line of centre of object, which is a half-width away
773 // from the end position
776 * <-- start pos <-----><-- positionOnLineX
778 * --------------| x | <-- e.g. rectangular arrowhead
782 GetPointOnLine(startPositionX
, startPositionY
,
783 positionOnLineX
, positionOnLineY
,
784 (double)(arrow
->GetMetaFile()->m_width
/2.0),
787 // Calculate theta for rotating the metafile.
790 | o(x2, y2) 'o' represents the arrowhead.
795 |______________________
798 double x1
= startPositionX
;
799 double y1
= startPositionY
;
800 double x2
= positionOnLineX
;
801 double y2
= positionOnLineY
;
803 if ((x1
== x2
) && (y1
== y2
))
806 else if ((x1
== x2
) && (y1
> y2
))
807 theta
= (double)(3.0*myPi
/2.0);
809 else if ((x1
== x2
) && (y2
> y1
))
810 theta
= (double)(myPi
/2.0);
812 else if ((x2
> x1
) && (y2
>= y1
))
813 theta
= (double)atan((y2
- y1
)/(x2
- x1
));
816 theta
= (double)(myPi
+ atan((y2
- y1
)/(x2
- x1
)));
818 else if ((x2
> x1
) && (y2
< y1
))
819 theta
= (double)(2*myPi
+ atan((y2
- y1
)/(x2
- x1
)));
823 wxLogFatalError(wxT("Unknown arrowhead rotation case in lines.cc"));
826 // Rotate about the centre of the object, then place
827 // the object on the line.
828 if (arrow
->GetMetaFile()->GetRotateable())
829 arrow
->GetMetaFile()->Rotate(0.0, 0.0, theta
);
833 // If erasing, just draw a rectangle.
834 double minX
, minY
, maxX
, maxY
;
835 arrow
->GetMetaFile()->GetBounds(&minX
, &minY
, &maxX
, &maxY
);
836 // Make erasing rectangle slightly bigger or you get droppings.
838 dc
.DrawRectangle((long)(deltaX
+ x
+ minX
- (extraPixels
/2.0)), (long)(deltaY
+ y
+ minY
- (extraPixels
/2.0)),
839 (long)(maxX
- minX
+ extraPixels
), (long)(maxY
- minY
+ extraPixels
));
842 arrow
->GetMetaFile()->Draw(dc
, x
+deltaX
, y
+deltaY
);
852 void wxLineShape::OnErase(wxDC
& dc
)
854 wxPen
*old_pen
= m_pen
;
855 wxBrush
*old_brush
= m_brush
;
856 wxPen bg_pen
= GetBackgroundPen();
857 wxBrush bg_brush
= GetBackgroundBrush();
861 double bound_x
, bound_y
;
862 GetBoundingBoxMax(&bound_x
, &bound_y
);
863 if (m_font
) dc
.SetFont(* m_font
);
865 // Undraw text regions
866 for (int i
= 0; i
< 3; i
++)
868 wxNode
*node
= m_regions
.Nth(i
);
872 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
873 GetLabelPosition(i
, &x
, &y
);
874 EraseRegion(dc
, region
, x
, y
);
879 dc
.SetPen(GetBackgroundPen());
880 dc
.SetBrush(GetBackgroundBrush());
882 // Drawing over the line only seems to work if the line has a thickness
884 if (old_pen
&& (old_pen
->GetWidth() > 1))
886 dc
.DrawRectangle((long)(m_xpos
- (bound_x
/2.0) - 2.0), (long)(m_ypos
- (bound_y
/2.0) - 2.0),
887 (long)(bound_x
+4.0), (long)(bound_y
+4.0));
892 GetEventHandler()->OnDraw(dc
);
893 GetEventHandler()->OnEraseControlPoints(dc
);
897 if (old_pen
) SetPen(old_pen
);
898 if (old_brush
) SetBrush(old_brush
);
901 void wxLineShape::GetBoundingBoxMin(double *w
, double *h
)
908 wxNode
*node
= m_lineControlPoints
->First();
911 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
913 if (point
->x
< x1
) x1
= point
->x
;
914 if (point
->y
< y1
) y1
= point
->y
;
915 if (point
->x
> x2
) x2
= point
->x
;
916 if (point
->y
> y2
) y2
= point
->y
;
920 *w
= (double)(x2
- x1
);
921 *h
= (double)(y2
- y1
);
925 * For a node image of interest, finds the position of this arc
926 * amongst all the arcs which are attached to THIS SIDE of the node image,
927 * and the number of same.
929 void wxLineShape::FindNth(wxShape
*image
, int *nth
, int *no_arcs
, bool incoming
)
933 wxNode
*node
= image
->GetLines().First();
936 this_attachment
= m_attachmentTo
;
938 this_attachment
= m_attachmentFrom
;
940 // Find number of lines going into/out of this particular attachment point
943 wxLineShape
*line
= (wxLineShape
*)node
->Data();
945 if (line
->m_from
== image
)
947 // This is the nth line attached to 'image'
948 if ((line
== this) && !incoming
)
951 // Increment num count if this is the same side (attachment number)
952 if (line
->m_attachmentFrom
== this_attachment
)
956 if (line
->m_to
== image
)
958 // This is the nth line attached to 'image'
959 if ((line
== this) && incoming
)
962 // Increment num count if this is the same side (attachment number)
963 if (line
->m_attachmentTo
== this_attachment
)
973 void wxLineShape::OnDrawOutline(wxDC
& dc
, double x
, double y
, double w
, double h
)
975 wxPen
*old_pen
= m_pen
;
976 wxBrush
*old_brush
= m_brush
;
978 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
980 SetBrush( wxTRANSPARENT_BRUSH
);
982 GetEventHandler()->OnDraw(dc
);
984 if (old_pen
) SetPen(old_pen
);
986 if (old_brush
) SetBrush(old_brush
);
990 bool wxLineShape::OnMovePre(wxDC
& dc
, double x
, double y
, double old_x
, double old_y
, bool display
)
992 double x_offset
= x
- old_x
;
993 double 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 double 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.
1043 double end_x
, end_y
;
1044 double 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 double oldX
= m_xpos
;
1059 double 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 double x_offset
= m_xpos
- oldX
;
1069 double 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() != ATTACHMENT_MODE_NONE
) && 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(double *fromX
, double *fromY
, double *toX
, double *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.
1102 double end_x
, end_y
;
1103 double 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() != ATTACHMENT_MODE_NONE
)
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 (double)second_point
->x
, (double)second_point
->y
,
1129 if (m_to
->GetAttachmentMode() != ATTACHMENT_MODE_NONE
)
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 (double)second_last_point
->x
, (double)second_last_point
->y
,
1138 &other_end_x
, &other_end_y
);
1142 double fromX
= m_from
->GetX();
1143 double fromY
= m_from
->GetY();
1144 double toX
= m_to
->GetX();
1145 double toY
= m_to
->GetY();
1147 if (m_from
->GetAttachmentMode() != ATTACHMENT_MODE_NONE
)
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() != ATTACHMENT_MODE_NONE
)
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() == ATTACHMENT_MODE_NONE
)
1166 (void) m_from
->GetPerimeterPoint(m_from
->GetX(), m_from
->GetY(),
1170 if (m_to
->GetAttachmentMode() == ATTACHMENT_MODE_NONE
)
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
= WXROUND(point
->x
);
1197 points
[i
].y
= WXROUND(point
->y
);
1201 dc
.DrawSpline(n
, points
);
1203 dc
.DrawLines(n
, points
);
1206 // For some reason, last point isn't drawn under Windows.
1207 dc
.DrawPoint(points
[n
-1]);
1213 // Problem with pen - if not a solid pen, does strange things
1214 // to the arrowhead. So make (get) a new pen that's solid.
1215 if (m_pen
&& (m_pen
->GetStyle() != wxSOLID
))
1218 wxThePenList
->FindOrCreatePen(m_pen
->GetColour(), 1, wxSOLID
);
1220 dc
.SetPen(* solid_pen
);
1226 void wxLineShape::OnDrawControlPoints(wxDC
& dc
)
1231 // Draw temporary label rectangles if necessary
1232 for (int i
= 0; i
< 3; i
++)
1234 if (m_labelObjects
[i
])
1235 m_labelObjects
[i
]->Draw(dc
);
1237 wxShape::OnDrawControlPoints(dc
);
1240 void wxLineShape::OnEraseControlPoints(wxDC
& dc
)
1242 // Erase temporary label rectangles if necessary
1243 for (int i
= 0; i
< 3; i
++)
1245 if (m_labelObjects
[i
])
1246 m_labelObjects
[i
]->Erase(dc
);
1248 wxShape::OnEraseControlPoints(dc
);
1251 void wxLineShape::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
1255 void wxLineShape::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
1259 void wxLineShape::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
1264 void wxLineShape::SetArrowSize(double length, double width)
1266 arrow_length = length;
1267 arrow_width = width;
1270 void wxLineShape::SetStartArrow(int style)
1272 start_style = style;
1275 void wxLineShape::SetMiddleArrow(int style)
1277 middle_style = style;
1280 void wxLineShape::SetEndArrow(int style)
1286 void wxLineShape::OnDrawContents(wxDC
& dc
)
1288 if (GetDisableLabel())
1291 for (int i
= 0; i
< 3; i
++)
1293 wxNode
*node
= m_regions
.Nth(i
);
1296 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
1298 GetLabelPosition(i
, &x
, &y
);
1299 DrawRegion(dc
, region
, x
, y
);
1304 void wxLineShape::SetTo(wxShape
*object
)
1309 void wxLineShape::SetFrom(wxShape
*object
)
1314 void wxLineShape::MakeControlPoints()
1316 if (m_canvas
&& m_lineControlPoints
)
1318 wxNode
*first
= m_lineControlPoints
->First();
1319 wxNode
*last
= m_lineControlPoints
->Last();
1320 wxRealPoint
*first_point
= (wxRealPoint
*)first
->Data();
1321 wxRealPoint
*last_point
= (wxRealPoint
*)last
->Data();
1323 wxLineControlPoint
*control
= new wxLineControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
,
1324 first_point
->x
, first_point
->y
,
1325 CONTROL_POINT_ENDPOINT_FROM
);
1326 control
->m_point
= first_point
;
1327 m_canvas
->AddShape(control
);
1328 m_controlPoints
.Append(control
);
1331 wxNode
*node
= first
->Next();
1332 while (node
!= last
)
1334 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
1336 control
= new wxLineControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
,
1338 CONTROL_POINT_LINE
);
1339 control
->m_point
= point
;
1341 m_canvas
->AddShape(control
);
1342 m_controlPoints
.Append(control
);
1344 node
= node
->Next();
1346 control
= new wxLineControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
,
1347 last_point
->x
, last_point
->y
,
1348 CONTROL_POINT_ENDPOINT_TO
);
1349 control
->m_point
= last_point
;
1350 m_canvas
->AddShape(control
);
1351 m_controlPoints
.Append(control
);
1357 void wxLineShape::ResetControlPoints()
1359 if (m_canvas
&& m_lineControlPoints
&& m_controlPoints
.Number() > 0)
1361 wxNode
*node
= m_controlPoints
.First();
1362 wxNode
*control_node
= m_lineControlPoints
->First();
1363 while (node
&& control_node
)
1365 wxRealPoint
*point
= (wxRealPoint
*)control_node
->Data();
1366 wxLineControlPoint
*control
= (wxLineControlPoint
*)node
->Data();
1367 control
->SetX(point
->x
);
1368 control
->SetY(point
->y
);
1370 node
= node
->Next();
1371 control_node
= control_node
->Next();
1377 void wxLineShape::WriteAttributes(wxExpr
*clause
)
1379 wxShape::WriteAttributes(clause
);
1382 clause
->AddAttributeValue("from", m_from
->GetId());
1384 clause
->AddAttributeValue("to", m_to
->GetId());
1386 if (m_attachmentTo
!= 0)
1387 clause
->AddAttributeValue("attachment_to", (long)m_attachmentTo
);
1388 if (m_attachmentFrom
!= 0)
1389 clause
->AddAttributeValue("attachment_from", (long)m_attachmentFrom
);
1391 if (m_alignmentStart
!= 0)
1392 clause
->AddAttributeValue("align_start", (long)m_alignmentStart
);
1393 if (m_alignmentEnd
!= 0)
1394 clause
->AddAttributeValue("align_end", (long)m_alignmentEnd
);
1396 clause
->AddAttributeValue("is_spline", (long)m_isSpline
);
1397 if (m_maintainStraightLines
)
1398 clause
->AddAttributeValue("keep_lines_straight", (long)m_maintainStraightLines
);
1400 // Make a list of lists for the (sp)line controls
1401 wxExpr
*list
= new wxExpr(wxExprList
);
1402 wxNode
*node
= m_lineControlPoints
->First();
1405 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
1406 wxExpr
*point_list
= new wxExpr(wxExprList
);
1407 wxExpr
*x_expr
= new wxExpr((double) point
->x
);
1408 wxExpr
*y_expr
= new wxExpr((double) point
->y
);
1409 point_list
->Append(x_expr
);
1410 point_list
->Append(y_expr
);
1411 list
->Append(point_list
);
1413 node
= node
->Next();
1415 clause
->AddAttributeValue("controls", list
);
1417 // Write arc arrows in new OGL format, if there are any.
1418 // This is a list of lists. Each sublist comprises:
1419 // (arrowType arrowEnd xOffset arrowSize)
1420 if (m_arcArrows
.Number() > 0)
1422 wxExpr
*arrow_list
= new wxExpr(wxExprList
);
1423 node
= m_arcArrows
.First();
1426 wxArrowHead
*head
= (wxArrowHead
*)node
->Data();
1427 wxExpr
*head_list
= new wxExpr(wxExprList
);
1428 head_list
->Append(new wxExpr((long)head
->_GetType()));
1429 head_list
->Append(new wxExpr((long)head
->GetArrowEnd()));
1430 head_list
->Append(new wxExpr(head
->GetXOffset()));
1431 head_list
->Append(new wxExpr(head
->GetArrowSize()));
1432 head_list
->Append(new wxExpr(wxExprString
, head
->GetName()));
1433 head_list
->Append(new wxExpr(head
->GetId()));
1435 // New members of wxArrowHead
1436 head_list
->Append(new wxExpr(head
->GetYOffset()));
1437 head_list
->Append(new wxExpr(head
->GetSpacing()));
1439 arrow_list
->Append(head_list
);
1441 node
= node
->Next();
1443 clause
->AddAttributeValue("arrows", arrow_list
);
1447 void wxLineShape::ReadAttributes(wxExpr
*clause
)
1449 wxShape::ReadAttributes(clause
);
1451 int iVal
= (int) m_isSpline
;
1452 clause
->AssignAttributeValue(wxT("is_spline"), &iVal
);
1453 m_isSpline
= (iVal
!= 0);
1455 iVal
= (int) m_maintainStraightLines
;
1456 clause
->AssignAttributeValue(wxT("keep_lines_straight"), &iVal
);
1457 m_maintainStraightLines
= (iVal
!= 0);
1459 clause
->AssignAttributeValue(wxT("align_start"), &m_alignmentStart
);
1460 clause
->AssignAttributeValue(wxT("align_end"), &m_alignmentEnd
);
1462 // Compatibility: check for no regions.
1463 if (m_regions
.Number() == 0)
1465 wxShapeRegion
*newRegion
= new wxShapeRegion
;
1466 newRegion
->SetName("Middle");
1467 newRegion
->SetSize(150, 50);
1468 m_regions
.Append((wxObject
*)newRegion
);
1469 if (m_text
.Number() > 0)
1471 newRegion
->ClearText();
1472 wxNode
*node
= m_text
.First();
1475 wxShapeTextLine
*textLine
= (wxShapeTextLine
*)node
->Data();
1476 wxNode
*next
= node
->Next();
1477 newRegion
->GetFormattedText().Append((wxObject
*)textLine
);
1483 newRegion
= new wxShapeRegion
;
1484 newRegion
->SetName(wxT("Start"));
1485 newRegion
->SetSize(150, 50);
1486 m_regions
.Append((wxObject
*)newRegion
);
1488 newRegion
= new wxShapeRegion
;
1489 newRegion
->SetName(wxT("End"));
1490 newRegion
->SetSize(150, 50);
1491 m_regions
.Append((wxObject
*)newRegion
);
1495 m_attachmentFrom
= 0;
1497 clause
->AssignAttributeValue(wxT("attachment_to"), &m_attachmentTo
);
1498 clause
->AssignAttributeValue(wxT("attachment_from"), &m_attachmentFrom
);
1500 wxExpr
*line_list
= NULL
;
1502 // When image is created, there are default control points. Override
1503 // them if there are some in the file.
1504 clause
->AssignAttributeValue(wxT("controls"), &line_list
);
1508 // Read a list of lists for the spline controls
1509 if (m_lineControlPoints
)
1511 ClearPointList(*m_lineControlPoints
);
1514 m_lineControlPoints
= new wxList
;
1516 wxExpr
*node
= line_list
->value
.first
;
1520 wxExpr
*xexpr
= node
->value
.first
;
1521 double x
= xexpr
->RealValue();
1523 wxExpr
*yexpr
= xexpr
->next
;
1524 double y
= yexpr
->RealValue();
1526 wxRealPoint
*point
= new wxRealPoint(x
, y
);
1527 m_lineControlPoints
->Append((wxObject
*) point
);
1533 // Read arrow list, for new OGL code
1534 wxExpr
*arrow_list
= NULL
;
1536 clause
->AssignAttributeValue(wxT("arrows"), &arrow_list
);
1539 wxExpr
*node
= arrow_list
->value
.first
;
1543 WXTYPE arrowType
= ARROW_ARROW
;
1545 double xOffset
= 0.0;
1546 double arrowSize
= 0.0;
1550 wxExpr
*type_expr
= node
->Nth(0);
1551 wxExpr
*end_expr
= node
->Nth(1);
1552 wxExpr
*dist_expr
= node
->Nth(2);
1553 wxExpr
*size_expr
= node
->Nth(3);
1554 wxExpr
*name_expr
= node
->Nth(4);
1555 wxExpr
*id_expr
= node
->Nth(5);
1557 // New members of wxArrowHead
1558 wxExpr
*yOffsetExpr
= node
->Nth(6);
1559 wxExpr
*spacingExpr
= node
->Nth(7);
1562 arrowType
= (int)type_expr
->IntegerValue();
1564 arrowEnd
= (int)end_expr
->IntegerValue();
1566 xOffset
= dist_expr
->RealValue();
1568 arrowSize
= size_expr
->RealValue();
1570 arrowName
= name_expr
->StringValue();
1572 arrowId
= id_expr
->IntegerValue();
1575 arrowId
= wxNewId();
1577 wxRegisterId(arrowId
);
1579 wxArrowHead
*arrowHead
= AddArrow(arrowType
, arrowEnd
, arrowSize
, xOffset
, arrowName
, NULL
, arrowId
);
1581 arrowHead
->SetYOffset(yOffsetExpr
->RealValue());
1583 arrowHead
->SetSpacing(spacingExpr
->RealValue());
1591 void wxLineShape::Copy(wxShape
& copy
)
1593 wxShape::Copy(copy
);
1595 wxASSERT( copy
.IsKindOf(CLASSINFO(wxLineShape
)) );
1597 wxLineShape
& lineCopy
= (wxLineShape
&) copy
;
1599 lineCopy
.m_to
= m_to
;
1600 lineCopy
.m_from
= m_from
;
1601 lineCopy
.m_attachmentTo
= m_attachmentTo
;
1602 lineCopy
.m_attachmentFrom
= m_attachmentFrom
;
1603 lineCopy
.m_isSpline
= m_isSpline
;
1604 lineCopy
.m_alignmentStart
= m_alignmentStart
;
1605 lineCopy
.m_alignmentEnd
= m_alignmentEnd
;
1606 lineCopy
.m_maintainStraightLines
= m_maintainStraightLines
;
1607 lineCopy
.m_lineOrientations
.Clear();
1609 wxNode
*node
= m_lineOrientations
.First();
1612 lineCopy
.m_lineOrientations
.Append(node
->Data());
1613 node
= node
->Next();
1616 if (lineCopy
.m_lineControlPoints
)
1618 ClearPointList(*lineCopy
.m_lineControlPoints
);
1619 delete lineCopy
.m_lineControlPoints
;
1622 lineCopy
.m_lineControlPoints
= new wxList
;
1624 node
= m_lineControlPoints
->First();
1627 wxRealPoint
*point
= (wxRealPoint
*)node
->Data();
1628 wxRealPoint
*new_point
= new wxRealPoint(point
->x
, point
->y
);
1629 lineCopy
.m_lineControlPoints
->Append((wxObject
*) new_point
);
1630 node
= node
->Next();
1634 lineCopy
.ClearArrowsAtPosition(-1);
1635 node
= m_arcArrows
.First();
1638 wxArrowHead
*arrow
= (wxArrowHead
*)node
->Data();
1639 lineCopy
.m_arcArrows
.Append(new wxArrowHead(*arrow
));
1640 node
= node
->Next();
1644 // Override select, to create/delete temporary label-moving objects
1645 void wxLineShape::Select(bool select
, wxDC
* dc
)
1647 wxShape::Select(select
, dc
);
1650 for (int i
= 0; i
< 3; i
++)
1652 wxNode
*node
= m_regions
.Nth(i
);
1655 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
1656 if (region
->m_formattedText
.Number() > 0)
1658 double w
, h
, x
, y
, xx
, yy
;
1659 region
->GetSize(&w
, &h
);
1660 region
->GetPosition(&x
, &y
);
1661 GetLabelPosition(i
, &xx
, &yy
);
1662 if (m_labelObjects
[i
])
1664 m_labelObjects
[i
]->Select(FALSE
);
1665 m_labelObjects
[i
]->RemoveFromCanvas(m_canvas
);
1666 delete m_labelObjects
[i
];
1668 m_labelObjects
[i
] = OnCreateLabelShape(this, region
, w
, h
);
1669 m_labelObjects
[i
]->AddToCanvas(m_canvas
);
1670 m_labelObjects
[i
]->Show(TRUE
);
1672 m_labelObjects
[i
]->Move(*dc
, (double)(x
+ xx
), (double)(y
+ yy
));
1673 m_labelObjects
[i
]->Select(TRUE
, dc
);
1680 for (int i
= 0; i
< 3; i
++)
1682 if (m_labelObjects
[i
])
1684 m_labelObjects
[i
]->Select(FALSE
, dc
);
1685 m_labelObjects
[i
]->Erase(*dc
);
1686 m_labelObjects
[i
]->RemoveFromCanvas(m_canvas
);
1687 delete m_labelObjects
[i
];
1688 m_labelObjects
[i
] = NULL
;
1695 * Line control point
1699 IMPLEMENT_DYNAMIC_CLASS(wxLineControlPoint
, wxControlPoint
)
1701 wxLineControlPoint::wxLineControlPoint(wxShapeCanvas
*theCanvas
, wxShape
*object
, double size
, double x
, double y
, int the_type
):
1702 wxControlPoint(theCanvas
, object
, size
, x
, y
, the_type
)
1710 wxLineControlPoint::~wxLineControlPoint()
1714 void wxLineControlPoint::OnDraw(wxDC
& dc
)
1716 wxRectangleShape::OnDraw(dc
);
1719 // Implement movement of Line point
1720 void wxLineControlPoint::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
1722 m_shape
->GetEventHandler()->OnSizingDragLeft(this, draw
, x
, y
, keys
, attachment
);
1725 void wxLineControlPoint::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
1727 m_shape
->GetEventHandler()->OnSizingBeginDragLeft(this, x
, y
, keys
, attachment
);
1730 void wxLineControlPoint::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
1732 m_shape
->GetEventHandler()->OnSizingEndDragLeft(this, x
, y
, keys
, attachment
);
1735 // Control points ('handles') redirect control to the actual shape, to make it easier
1736 // to override sizing behaviour.
1737 void wxLineShape::OnSizingDragLeft(wxControlPoint
* pt
, bool draw
, double x
, double y
, int keys
, int attachment
)
1739 wxLineControlPoint
* lpt
= (wxLineControlPoint
*) pt
;
1741 wxClientDC
dc(GetCanvas());
1742 GetCanvas()->PrepareDC(dc
);
1744 dc
.SetLogicalFunction(OGLRBLF
);
1746 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1747 dc
.SetPen(dottedPen
);
1748 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1750 if (lpt
->m_type
== CONTROL_POINT_LINE
)
1752 m_canvas
->Snap(&x
, &y
);
1754 lpt
->SetX(x
); lpt
->SetY(y
);
1755 lpt
->m_point
->x
= x
; lpt
->m_point
->y
= y
;
1757 wxLineShape
*lineShape
= (wxLineShape
*)this;
1759 wxPen
*old_pen
= lineShape
->GetPen();
1760 wxBrush
*old_brush
= lineShape
->GetBrush();
1762 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1763 lineShape
->SetPen(& dottedPen
);
1764 lineShape
->SetBrush(wxTRANSPARENT_BRUSH
);
1766 lineShape
->GetEventHandler()->OnMoveLink(dc
, FALSE
);
1768 lineShape
->SetPen(old_pen
);
1769 lineShape
->SetBrush(old_brush
);
1772 if (lpt
->m_type
== CONTROL_POINT_ENDPOINT_FROM
|| lpt
->m_type
== CONTROL_POINT_ENDPOINT_TO
)
1774 // lpt->SetX(x); lpt->SetY(y);
1779 void wxLineShape::OnSizingBeginDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int attachment
)
1781 wxLineControlPoint
* lpt
= (wxLineControlPoint
*) pt
;
1783 wxClientDC
dc(GetCanvas());
1784 GetCanvas()->PrepareDC(dc
);
1786 wxLineShape
*lineShape
= (wxLineShape
*)this;
1787 if (lpt
->m_type
== CONTROL_POINT_LINE
)
1789 lpt
->m_originalPos
= * (lpt
->m_point
);
1790 m_canvas
->Snap(&x
, &y
);
1794 // Redraw start and end objects because we've left holes
1795 // when erasing the line
1796 lineShape
->GetFrom()->OnDraw(dc
);
1797 lineShape
->GetFrom()->OnDrawContents(dc
);
1798 lineShape
->GetTo()->OnDraw(dc
);
1799 lineShape
->GetTo()->OnDrawContents(dc
);
1801 this->SetDisableLabel(TRUE
);
1802 dc
.SetLogicalFunction(OGLRBLF
);
1804 lpt
->m_xpos
= x
; lpt
->m_ypos
= y
;
1805 lpt
->m_point
->x
= x
; lpt
->m_point
->y
= y
;
1807 wxPen
*old_pen
= lineShape
->GetPen();
1808 wxBrush
*old_brush
= lineShape
->GetBrush();
1810 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1811 lineShape
->SetPen(& dottedPen
);
1812 lineShape
->SetBrush(wxTRANSPARENT_BRUSH
);
1814 lineShape
->GetEventHandler()->OnMoveLink(dc
, FALSE
);
1816 lineShape
->SetPen(old_pen
);
1817 lineShape
->SetBrush(old_brush
);
1820 if (lpt
->m_type
== CONTROL_POINT_ENDPOINT_FROM
|| lpt
->m_type
== CONTROL_POINT_ENDPOINT_TO
)
1822 m_canvas
->SetCursor(wxCursor(wxCURSOR_BULLSEYE
));
1823 lpt
->m_oldCursor
= wxSTANDARD_CURSOR
;
1827 void wxLineShape::OnSizingEndDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int attachment
)
1829 wxLineControlPoint
* lpt
= (wxLineControlPoint
*) pt
;
1831 wxClientDC
dc(GetCanvas());
1832 GetCanvas()->PrepareDC(dc
);
1834 this->SetDisableLabel(FALSE
);
1835 wxLineShape
*lineShape
= (wxLineShape
*)this;
1837 if (lpt
->m_type
== CONTROL_POINT_LINE
)
1839 m_canvas
->Snap(&x
, &y
);
1841 wxRealPoint pt
= wxRealPoint(x
, y
);
1843 // Move the control point back to where it was;
1844 // MoveControlPoint will move it to the new position
1845 // if it decides it wants. We only moved the position
1846 // during user feedback so we could redraw the line
1847 // as it changed shape.
1848 lpt
->m_xpos
= lpt
->m_originalPos
.x
; lpt
->m_ypos
= lpt
->m_originalPos
.y
;
1849 lpt
->m_point
->x
= lpt
->m_originalPos
.x
; lpt
->m_point
->y
= lpt
->m_originalPos
.y
;
1851 OnMoveMiddleControlPoint(dc
, lpt
, pt
);
1853 if (lpt
->m_type
== CONTROL_POINT_ENDPOINT_FROM
)
1855 if (lpt
->m_oldCursor
)
1856 m_canvas
->SetCursor(* lpt
->m_oldCursor
);
1860 // lpt->m_xpos = x; lpt->m_ypos = y;
1862 if (lineShape
->GetFrom())
1864 lineShape
->GetFrom()->MoveLineToNewAttachment(dc
, lineShape
, x
, y
);
1867 if (lpt
->m_type
== CONTROL_POINT_ENDPOINT_TO
)
1869 if (lpt
->m_oldCursor
)
1870 m_canvas
->SetCursor(* lpt
->m_oldCursor
);
1872 // lpt->m_xpos = x; lpt->m_ypos = y;
1874 if (lineShape
->GetTo())
1876 lineShape
->GetTo()->MoveLineToNewAttachment(dc
, lineShape
, x
, y
);
1883 for (i
= 0; i
< lineShape
->GetLineControlPoints()->Number(); i
++)
1884 if (((wxRealPoint
*)(lineShape
->GetLineControlPoints()->Nth(i
)->Data())) == lpt
->m_point
)
1887 // N.B. in OnMoveControlPoint, an event handler in Hardy could have deselected
1888 // the line and therefore deleted 'this'. -> GPF, intermittently.
1889 // So assume at this point that we've been blown away.
1891 lineShape
->OnMoveControlPoint(i
+1, x
, y
);
1895 // This is called only when a non-end control point is moved.
1896 bool wxLineShape::OnMoveMiddleControlPoint(wxDC
& dc
, wxLineControlPoint
* lpt
, const wxRealPoint
& pt
)
1898 lpt
->m_xpos
= pt
.x
; lpt
->m_ypos
= pt
.y
;
1899 lpt
->m_point
->x
= pt
.x
; lpt
->m_point
->y
= pt
.y
;
1901 GetEventHandler()->OnMoveLink(dc
);
1906 // Implement movement of endpoint to a new attachment
1907 // OBSOLETE: done by dragging with the left button.
1910 void wxLineControlPoint::OnDragRight(bool draw
, double x
, double y
, int keys
, int attachment
)
1912 if (m_type
== CONTROL_POINT_ENDPOINT_FROM
|| m_type
== CONTROL_POINT_ENDPOINT_TO
)
1914 m_xpos
= x
; m_ypos
= y
;
1918 void wxLineControlPoint::OnBeginDragRight(double x
, double y
, int keys
, int attachment
)
1920 wxClientDC
dc(GetCanvas());
1921 GetCanvas()->PrepareDC(dc
);
1923 wxLineShape
*lineShape
= (wxLineShape
*)m_shape
;
1924 if (m_type
== CONTROL_POINT_ENDPOINT_FROM
|| m_type
== CONTROL_POINT_ENDPOINT_TO
)
1927 lineShape
->GetEventHandler()->OnDraw(dc
);
1928 if (m_type
== CONTROL_POINT_ENDPOINT_FROM
)
1930 lineShape
->GetFrom()->GetEventHandler()->OnDraw(dc
);
1931 lineShape
->GetFrom()->GetEventHandler()->OnDrawContents(dc
);
1935 lineShape
->GetTo()->GetEventHandler()->OnDraw(dc
);
1936 lineShape
->GetTo()->GetEventHandler()->OnDrawContents(dc
);
1938 m_canvas
->SetCursor(wxCursor(wxCURSOR_BULLSEYE
));
1939 m_oldCursor
= wxSTANDARD_CURSOR
;
1943 void wxLineControlPoint::OnEndDragRight(double x
, double y
, int keys
, int attachment
)
1945 wxClientDC
dc(GetCanvas());
1946 GetCanvas()->PrepareDC(dc
);
1948 wxLineShape
*lineShape
= (wxLineShape
*)m_shape
;
1949 if (m_type
== CONTROL_POINT_ENDPOINT_FROM
)
1952 m_canvas
->SetCursor(m_oldCursor
);
1954 m_xpos
= x
; m_ypos
= y
;
1956 if (lineShape
->GetFrom())
1958 lineShape
->GetFrom()->EraseLinks(dc
);
1963 if (lineShape
->GetFrom()->HitTest(x
, y
, &new_attachment
, &distance
))
1964 lineShape
->SetAttachments(new_attachment
, lineShape
->GetAttachmentTo());
1966 lineShape
->GetFrom()->MoveLinks(dc
);
1969 if (m_type
== CONTROL_POINT_ENDPOINT_TO
)
1972 m_canvas
->SetCursor(m_oldCursor
);
1975 m_xpos
= x
; m_ypos
= y
;
1977 if (lineShape
->GetTo())
1979 lineShape
->GetTo()->EraseLinks(dc
);
1983 if (lineShape
->GetTo()->HitTest(x
, y
, &new_attachment
, &distance
))
1984 lineShape
->SetAttachments(lineShape
->GetAttachmentFrom(), new_attachment
);
1986 lineShape
->GetTo()->MoveLinks(dc
);
1990 for (i
= 0; i
< lineShape
->GetLineControlPoints()->Number(); i
++)
1991 if (((wxRealPoint
*)(lineShape
->GetLineControlPoints()->Nth(i
)->Data())) == m_point
)
1993 lineShape
->OnMoveControlPoint(i
+1, x
, y
);
1994 if (!m_canvas
->GetQuickEditMode()) m_canvas
->Redraw(dc
);
1999 * Get the point on the given line (x1, y1) (x2, y2)
2000 * distance 'length' along from the end,
2001 * returned values in x and y
2004 void GetPointOnLine(double x1
, double y1
, double x2
, double y2
,
2005 double length
, double *x
, double *y
)
2007 double l
= (double)sqrt((x2
- x1
)*(x2
- x1
) + (y2
- y1
)*(y2
- y1
));
2012 double i_bar
= (x2
- x1
)/l
;
2013 double j_bar
= (y2
- y1
)/l
;
2015 *x
= (- length
*i_bar
) + x2
;
2016 *y
= (- length
*j_bar
) + y2
;
2019 wxArrowHead
*wxLineShape::AddArrow(WXTYPE type
, int end
, double size
, double xOffset
,
2020 const wxString
& name
, wxPseudoMetaFile
*mf
, long arrowId
)
2022 wxArrowHead
*arrow
= new wxArrowHead(type
, end
, size
, xOffset
, name
, mf
, arrowId
);
2023 m_arcArrows
.Append(arrow
);
2028 * Add arrowhead at a particular position in the arrowhead list.
2030 bool wxLineShape::AddArrowOrdered(wxArrowHead
*arrow
, wxList
& referenceList
, int end
)
2032 wxNode
*refNode
= referenceList
.First();
2033 wxNode
*currNode
= m_arcArrows
.First();
2034 wxString
targetName(arrow
->GetName());
2035 if (!refNode
) return FALSE
;
2037 // First check whether we need to insert in front of list,
2038 // because this arrowhead is the first in the reference
2039 // list and should therefore be first in the current list.
2040 wxArrowHead
*refArrow
= (wxArrowHead
*)refNode
->Data();
2041 if (refArrow
->GetName() == targetName
)
2043 m_arcArrows
.Insert(arrow
);
2047 while (refNode
&& currNode
)
2049 wxArrowHead
*currArrow
= (wxArrowHead
*)currNode
->Data();
2050 refArrow
= (wxArrowHead
*)refNode
->Data();
2052 // Matching: advance current arrow pointer
2053 if ((currArrow
->GetArrowEnd() == end
) &&
2054 (currArrow
->GetName() == refArrow
->GetName()))
2056 currNode
= currNode
->Next(); // Could be NULL now
2058 currArrow
= (wxArrowHead
*)currNode
->Data();
2061 // Check if we're at the correct position in the
2063 if (targetName
== refArrow
->GetName())
2066 m_arcArrows
.Insert(currNode
, arrow
);
2068 m_arcArrows
.Append(arrow
);
2071 refNode
= refNode
->Next();
2073 m_arcArrows
.Append(arrow
);
2077 void wxLineShape::ClearArrowsAtPosition(int end
)
2079 wxNode
*node
= m_arcArrows
.First();
2082 wxArrowHead
*arrow
= (wxArrowHead
*)node
->Data();
2083 wxNode
*next
= node
->Next();
2092 case ARROW_POSITION_START
:
2094 if (arrow
->GetArrowEnd() == ARROW_POSITION_START
)
2101 case ARROW_POSITION_END
:
2103 if (arrow
->GetArrowEnd() == ARROW_POSITION_END
)
2110 case ARROW_POSITION_MIDDLE
:
2112 if (arrow
->GetArrowEnd() == ARROW_POSITION_MIDDLE
)
2124 bool wxLineShape::ClearArrow(const wxString
& name
)
2126 wxNode
*node
= m_arcArrows
.First();
2129 wxArrowHead
*arrow
= (wxArrowHead
*)node
->Data();
2130 if (arrow
->GetName() == name
)
2136 node
= node
->Next();
2142 * Finds an arrowhead at the given position (if -1, any position)
2146 wxArrowHead
*wxLineShape::FindArrowHead(int position
, const wxString
& name
)
2148 wxNode
*node
= m_arcArrows
.First();
2151 wxArrowHead
*arrow
= (wxArrowHead
*)node
->Data();
2152 if (((position
== -1) || (position
== arrow
->GetArrowEnd())) &&
2153 (arrow
->GetName() == name
))
2155 node
= node
->Next();
2160 wxArrowHead
*wxLineShape::FindArrowHead(long arrowId
)
2162 wxNode
*node
= m_arcArrows
.First();
2165 wxArrowHead
*arrow
= (wxArrowHead
*)node
->Data();
2166 if (arrowId
== arrow
->GetId())
2168 node
= node
->Next();
2174 * Deletes an arrowhead at the given position (if -1, any position)
2178 bool wxLineShape::DeleteArrowHead(int position
, const wxString
& name
)
2180 wxNode
*node
= m_arcArrows
.First();
2183 wxArrowHead
*arrow
= (wxArrowHead
*)node
->Data();
2184 if (((position
== -1) || (position
== arrow
->GetArrowEnd())) &&
2185 (arrow
->GetName() == name
))
2191 node
= node
->Next();
2196 // Overloaded DeleteArrowHead: pass arrowhead id.
2197 bool wxLineShape::DeleteArrowHead(long id
)
2199 wxNode
*node
= m_arcArrows
.First();
2202 wxArrowHead
*arrow
= (wxArrowHead
*)node
->Data();
2203 if (arrow
->GetId() == id
)
2209 node
= node
->Next();
2215 * Calculate the minimum width a line
2216 * occupies, for the purposes of drawing lines in tools.
2220 double wxLineShape::FindMinimumWidth()
2222 double minWidth
= 0.0;
2223 wxNode
*node
= m_arcArrows
.First();
2226 wxArrowHead
*arrowHead
= (wxArrowHead
*)node
->Data();
2227 minWidth
+= arrowHead
->GetSize();
2229 minWidth
+= arrowHead
->GetSpacing();
2231 node
= node
->Next();
2233 // We have ABSOLUTE minimum now. So
2234 // scale it to give it reasonable aesthetics
2235 // when drawing with line.
2237 minWidth
= (double)(minWidth
* 1.4);
2241 SetEnds(0.0, 0.0, minWidth
, 0.0);
2247 // Find which position we're talking about at this (x, y).
2248 // Returns ARROW_POSITION_START, ARROW_POSITION_MIDDLE, ARROW_POSITION_END
2249 int wxLineShape::FindLinePosition(double x
, double y
)
2251 double startX
, startY
, endX
, endY
;
2252 GetEnds(&startX
, &startY
, &endX
, &endY
);
2254 // Find distances from centre, start and end. The smallest wins.
2255 double centreDistance
= (double)(sqrt((x
- m_xpos
)*(x
- m_xpos
) + (y
- m_ypos
)*(y
- m_ypos
)));
2256 double startDistance
= (double)(sqrt((x
- startX
)*(x
- startX
) + (y
- startY
)*(y
- startY
)));
2257 double endDistance
= (double)(sqrt((x
- endX
)*(x
- endX
) + (y
- endY
)*(y
- endY
)));
2259 if (centreDistance
< startDistance
&& centreDistance
< endDistance
)
2260 return ARROW_POSITION_MIDDLE
;
2261 else if (startDistance
< endDistance
)
2262 return ARROW_POSITION_START
;
2264 return ARROW_POSITION_END
;
2267 // Set alignment flags
2268 void wxLineShape::SetAlignmentOrientation(bool isEnd
, bool isHoriz
)
2272 if (isHoriz
&& ((m_alignmentEnd
& LINE_ALIGNMENT_HORIZ
) != LINE_ALIGNMENT_HORIZ
))
2273 m_alignmentEnd
|= LINE_ALIGNMENT_HORIZ
;
2274 else if (!isHoriz
&& ((m_alignmentEnd
& LINE_ALIGNMENT_HORIZ
) == LINE_ALIGNMENT_HORIZ
))
2275 m_alignmentEnd
-= LINE_ALIGNMENT_HORIZ
;
2279 if (isHoriz
&& ((m_alignmentStart
& LINE_ALIGNMENT_HORIZ
) != LINE_ALIGNMENT_HORIZ
))
2280 m_alignmentStart
|= LINE_ALIGNMENT_HORIZ
;
2281 else if (!isHoriz
&& ((m_alignmentStart
& LINE_ALIGNMENT_HORIZ
) == LINE_ALIGNMENT_HORIZ
))
2282 m_alignmentStart
-= LINE_ALIGNMENT_HORIZ
;
2286 void wxLineShape::SetAlignmentType(bool isEnd
, int alignType
)
2290 if (alignType
== LINE_ALIGNMENT_TO_NEXT_HANDLE
)
2292 if ((m_alignmentEnd
& LINE_ALIGNMENT_TO_NEXT_HANDLE
) != LINE_ALIGNMENT_TO_NEXT_HANDLE
)
2293 m_alignmentEnd
|= LINE_ALIGNMENT_TO_NEXT_HANDLE
;
2295 else if ((m_alignmentEnd
& LINE_ALIGNMENT_TO_NEXT_HANDLE
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
)
2296 m_alignmentEnd
-= LINE_ALIGNMENT_TO_NEXT_HANDLE
;
2300 if (alignType
== LINE_ALIGNMENT_TO_NEXT_HANDLE
)
2302 if ((m_alignmentStart
& LINE_ALIGNMENT_TO_NEXT_HANDLE
) != LINE_ALIGNMENT_TO_NEXT_HANDLE
)
2303 m_alignmentStart
|= LINE_ALIGNMENT_TO_NEXT_HANDLE
;
2305 else if ((m_alignmentStart
& LINE_ALIGNMENT_TO_NEXT_HANDLE
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
)
2306 m_alignmentStart
-= LINE_ALIGNMENT_TO_NEXT_HANDLE
;
2310 bool wxLineShape::GetAlignmentOrientation(bool isEnd
)
2313 return ((m_alignmentEnd
& LINE_ALIGNMENT_HORIZ
) == LINE_ALIGNMENT_HORIZ
);
2315 return ((m_alignmentStart
& LINE_ALIGNMENT_HORIZ
) == LINE_ALIGNMENT_HORIZ
);
2318 int wxLineShape::GetAlignmentType(bool isEnd
)
2321 return (m_alignmentEnd
& LINE_ALIGNMENT_TO_NEXT_HANDLE
);
2323 return (m_alignmentStart
& LINE_ALIGNMENT_TO_NEXT_HANDLE
);
2326 wxRealPoint
*wxLineShape::GetNextControlPoint(wxShape
*nodeObject
)
2328 int n
= m_lineControlPoints
->Number();
2330 if (m_to
== nodeObject
)
2332 // Must be END of line, so we want (n - 1)th control point.
2333 // But indexing ends at n-1, so subtract 2.
2337 wxNode
*node
= m_lineControlPoints
->Nth(nn
);
2340 return (wxRealPoint
*)node
->Data();
2351 IMPLEMENT_DYNAMIC_CLASS(wxArrowHead
, wxObject
)
2353 wxArrowHead::wxArrowHead(WXTYPE type
, int end
, double size
, double dist
, const wxString
& name
,
2354 wxPseudoMetaFile
*mf
, long arrowId
)
2356 m_arrowType
= type
; m_arrowEnd
= end
; m_arrowSize
= size
;
2368 wxArrowHead::wxArrowHead(wxArrowHead
& toCopy
)
2370 m_arrowType
= toCopy
.m_arrowType
; m_arrowEnd
= toCopy
.GetArrowEnd();
2371 m_arrowSize
= toCopy
.m_arrowSize
;
2372 m_xOffset
= toCopy
.m_xOffset
;
2373 m_yOffset
= toCopy
.m_yOffset
;
2374 m_spacing
= toCopy
.m_spacing
;
2375 m_arrowName
= toCopy
.m_arrowName
;
2376 if (toCopy
.m_metaFile
)
2377 m_metaFile
= new wxPseudoMetaFile(*(toCopy
.m_metaFile
));
2383 wxArrowHead::~wxArrowHead()
2385 if (m_metaFile
) delete m_metaFile
;
2388 void wxArrowHead::SetSize(double size
)
2391 if ((m_arrowType
== ARROW_METAFILE
) && m_metaFile
)
2393 double oldWidth
= m_metaFile
->m_width
;
2394 if (oldWidth
== 0.0)
2397 double scale
= (double)(size
/oldWidth
);
2399 m_metaFile
->Scale(scale
, scale
);
2403 // Can override this to create a different class of label shape
2404 wxLabelShape
* wxLineShape::OnCreateLabelShape(wxLineShape
*parent
, wxShapeRegion
*region
, double w
, double h
)
2406 return new wxLabelShape(parent
, region
, w
, h
);
2414 IMPLEMENT_DYNAMIC_CLASS(wxLabelShape
, wxRectangleShape
)
2416 wxLabelShape::wxLabelShape(wxLineShape
*parent
, wxShapeRegion
*region
, double w
, double h
):wxRectangleShape(w
, h
)
2418 m_lineShape
= parent
;
2419 m_shapeRegion
= region
;
2420 SetPen(wxThePenList
->FindOrCreatePen(wxColour(0, 0, 0), 1, wxDOT
));
2423 wxLabelShape::~wxLabelShape()
2427 void wxLabelShape::OnDraw(wxDC
& dc
)
2429 if (m_lineShape
&& !m_lineShape
->GetDrawHandles())
2432 double x1
= (double)(m_xpos
- m_width
/2.0);
2433 double y1
= (double)(m_ypos
- m_height
/2.0);
2437 if (m_pen
->GetWidth() == 0)
2438 dc
.SetPen(* g_oglTransparentPen
);
2442 dc
.SetBrush(* wxTRANSPARENT_BRUSH
);
2444 if (m_cornerRadius
> 0.0)
2445 dc
.DrawRoundedRectangle(WXROUND(x1
), WXROUND(y1
), WXROUND(m_width
), WXROUND(m_height
), m_cornerRadius
);
2447 dc
.DrawRectangle(WXROUND(x1
), WXROUND(y1
), WXROUND(m_width
), WXROUND(m_height
));
2450 void wxLabelShape::OnDrawContents(wxDC
& dc
)
2454 void wxLabelShape::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
2456 wxRectangleShape::OnDragLeft(draw
, x
, y
, keys
, attachment
);
2459 void wxLabelShape::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
2461 wxRectangleShape::OnBeginDragLeft(x
, y
, keys
, attachment
);
2464 void wxLabelShape::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
2466 wxRectangleShape::OnEndDragLeft(x
, y
, keys
, attachment
);
2469 bool wxLabelShape::OnMovePre(wxDC
& dc
, double x
, double y
, double old_x
, double old_y
, bool display
)
2471 return m_lineShape
->OnLabelMovePre(dc
, this, x
, y
, old_x
, old_y
, display
);
2474 bool wxLineShape::OnLabelMovePre(wxDC
& dc
, wxLabelShape
* labelShape
, double x
, double y
, double old_x
, double old_y
, bool display
)
2476 labelShape
->m_shapeRegion
->SetSize(labelShape
->GetWidth(), labelShape
->GetHeight());
2478 // Find position in line's region list
2480 wxNode
*node
= GetRegions().First();
2483 if (labelShape
->m_shapeRegion
== (wxShapeRegion
*)node
->Data())
2487 node
= node
->Next();
2492 GetLabelPosition(i
, &xx
, &yy
);
2493 // Set the region's offset, relative to the default position for
2495 labelShape
->m_shapeRegion
->SetPosition((double)(x
- xx
), (double)(y
- yy
));
2497 labelShape
->SetX(x
);
2498 labelShape
->SetY(y
);
2500 // Need to reformat to fit region.
2501 if (labelShape
->m_shapeRegion
->GetText())
2504 wxString
s(labelShape
->m_shapeRegion
->GetText());
2505 labelShape
->FormatText(dc
, s
, i
);
2506 DrawRegion(dc
, labelShape
->m_shapeRegion
, xx
, yy
);
2511 // Divert left and right clicks to line object
2512 void wxLabelShape::OnLeftClick(double x
, double y
, int keys
, int attachment
)
2514 m_lineShape
->GetEventHandler()->OnLeftClick(x
, y
, keys
, attachment
);
2517 void wxLabelShape::OnRightClick(double x
, double y
, int keys
, int attachment
)
2519 m_lineShape
->GetEventHandler()->OnRightClick(x
, y
, keys
, attachment
);