1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Basic OGL classes
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "basic.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include <wx/wxprec.h>
28 #include <wx/wxexpr.h>
49 // Control point types
50 // Rectangle and most other shapes
51 #define CONTROL_POINT_VERTICAL 1
52 #define CONTROL_POINT_HORIZONTAL 2
53 #define CONTROL_POINT_DIAGONAL 3
56 #define CONTROL_POINT_ENDPOINT_TO 4
57 #define CONTROL_POINT_ENDPOINT_FROM 5
58 #define CONTROL_POINT_LINE 6
60 IMPLEMENT_DYNAMIC_CLASS(wxShapeTextLine
, wxObject
)
61 IMPLEMENT_DYNAMIC_CLASS(wxAttachmentPoint
, wxObject
)
63 wxShapeTextLine::wxShapeTextLine(double the_x
, double the_y
, const wxString
& the_line
)
65 m_x
= the_x
; m_y
= the_y
; m_line
= the_line
;
68 wxShapeTextLine::~wxShapeTextLine()
72 IMPLEMENT_ABSTRACT_CLASS(wxShapeEvtHandler
, wxObject
)
74 wxShapeEvtHandler::wxShapeEvtHandler(wxShapeEvtHandler
*prev
, wxShape
*shape
)
76 m_previousHandler
= prev
;
77 m_handlerShape
= shape
;
80 wxShapeEvtHandler::~wxShapeEvtHandler()
84 // Creates a copy of this event handler.
85 wxShapeEvtHandler
* wxShapeEvtHandler::CreateNewCopy()
87 wxShapeEvtHandler
* newObject
= (wxShapeEvtHandler
*) GetClassInfo()->CreateObject();
89 wxASSERT( (newObject
!= NULL
) );
90 wxASSERT( (newObject
->IsKindOf(CLASSINFO(wxShapeEvtHandler
))) );
92 newObject
->m_previousHandler
= newObject
;
100 void wxShapeEvtHandler::OnDelete()
102 if (this != GetShape())
106 void wxShapeEvtHandler::OnDraw(wxDC
& dc
)
108 if (m_previousHandler
)
109 m_previousHandler
->OnDraw(dc
);
112 void wxShapeEvtHandler::OnMoveLinks(wxDC
& dc
)
114 if (m_previousHandler
)
115 m_previousHandler
->OnMoveLinks(dc
);
118 void wxShapeEvtHandler::OnMoveLink(wxDC
& dc
, bool moveControlPoints
)
120 if (m_previousHandler
)
121 m_previousHandler
->OnMoveLink(dc
, moveControlPoints
);
124 void wxShapeEvtHandler::OnDrawContents(wxDC
& dc
)
126 if (m_previousHandler
)
127 m_previousHandler
->OnDrawContents(dc
);
130 void wxShapeEvtHandler::OnDrawBranches(wxDC
& dc
, bool erase
)
132 if (m_previousHandler
)
133 m_previousHandler
->OnDrawBranches(dc
, erase
);
136 void wxShapeEvtHandler::OnSize(double x
, double y
)
138 if (m_previousHandler
)
139 m_previousHandler
->OnSize(x
, y
);
142 bool wxShapeEvtHandler::OnMovePre(wxDC
& dc
, double x
, double y
, double old_x
, double old_y
, bool display
)
144 if (m_previousHandler
)
145 return m_previousHandler
->OnMovePre(dc
, x
, y
, old_x
, old_y
, display
);
150 void wxShapeEvtHandler::OnMovePost(wxDC
& dc
, double x
, double y
, double old_x
, double old_y
, bool display
)
152 if (m_previousHandler
)
153 m_previousHandler
->OnMovePost(dc
, x
, y
, old_x
, old_y
, display
);
156 void wxShapeEvtHandler::OnErase(wxDC
& dc
)
158 if (m_previousHandler
)
159 m_previousHandler
->OnErase(dc
);
162 void wxShapeEvtHandler::OnEraseContents(wxDC
& dc
)
164 if (m_previousHandler
)
165 m_previousHandler
->OnEraseContents(dc
);
168 void wxShapeEvtHandler::OnHighlight(wxDC
& dc
)
170 if (m_previousHandler
)
171 m_previousHandler
->OnHighlight(dc
);
174 void wxShapeEvtHandler::OnLeftClick(double x
, double y
, int keys
, int attachment
)
176 if (m_previousHandler
)
177 m_previousHandler
->OnLeftClick(x
, y
, keys
, attachment
);
180 void wxShapeEvtHandler::OnRightClick(double x
, double y
, int keys
, int attachment
)
182 if (m_previousHandler
)
183 m_previousHandler
->OnRightClick(x
, y
, keys
, attachment
);
186 void wxShapeEvtHandler::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
188 if (m_previousHandler
)
189 m_previousHandler
->OnDragLeft(draw
, x
, y
, keys
, attachment
);
192 void wxShapeEvtHandler::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
194 if (m_previousHandler
)
195 m_previousHandler
->OnBeginDragLeft(x
, y
, keys
, attachment
);
198 void wxShapeEvtHandler::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
200 if (m_previousHandler
)
201 m_previousHandler
->OnEndDragLeft(x
, y
, keys
, attachment
);
204 void wxShapeEvtHandler::OnDragRight(bool draw
, double x
, double y
, int keys
, int attachment
)
206 if (m_previousHandler
)
207 m_previousHandler
->OnDragRight(draw
, x
, y
, keys
, attachment
);
210 void wxShapeEvtHandler::OnBeginDragRight(double x
, double y
, int keys
, int attachment
)
212 if (m_previousHandler
)
213 m_previousHandler
->OnBeginDragRight(x
, y
, keys
, attachment
);
216 void wxShapeEvtHandler::OnEndDragRight(double x
, double y
, int keys
, int attachment
)
218 if (m_previousHandler
)
219 m_previousHandler
->OnEndDragRight(x
, y
, keys
, attachment
);
222 // Control points ('handles') redirect control to the actual shape, to make it easier
223 // to override sizing behaviour.
224 void wxShapeEvtHandler::OnSizingDragLeft(wxControlPoint
* pt
, bool draw
, double x
, double y
, int keys
, int attachment
)
226 if (m_previousHandler
)
227 m_previousHandler
->OnSizingDragLeft(pt
, draw
, x
, y
, keys
, attachment
);
230 void wxShapeEvtHandler::OnSizingBeginDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int attachment
)
232 if (m_previousHandler
)
233 m_previousHandler
->OnSizingBeginDragLeft(pt
, x
, y
, keys
, attachment
);
236 void wxShapeEvtHandler::OnSizingEndDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int attachment
)
238 if (m_previousHandler
)
239 m_previousHandler
->OnSizingEndDragLeft(pt
, x
, y
, keys
, attachment
);
242 void wxShapeEvtHandler::OnDrawOutline(wxDC
& dc
, double x
, double y
, double w
, double h
)
244 if (m_previousHandler
)
245 m_previousHandler
->OnDrawOutline(dc
, x
, y
, w
, h
);
248 void wxShapeEvtHandler::OnDrawControlPoints(wxDC
& dc
)
250 if (m_previousHandler
)
251 m_previousHandler
->OnDrawControlPoints(dc
);
254 void wxShapeEvtHandler::OnEraseControlPoints(wxDC
& dc
)
256 if (m_previousHandler
)
257 m_previousHandler
->OnEraseControlPoints(dc
);
260 // Can override this to prevent or intercept line reordering.
261 void wxShapeEvtHandler::OnChangeAttachment(int attachment
, wxLineShape
* line
, wxList
& ordering
)
263 if (m_previousHandler
)
264 m_previousHandler
->OnChangeAttachment(attachment
, line
, ordering
);
267 IMPLEMENT_ABSTRACT_CLASS(wxShape
, wxShapeEvtHandler
)
269 wxShape::wxShape(wxShapeCanvas
*can
)
271 m_eventHandler
= this;
276 m_xpos
= 0.0; m_ypos
= 0.0;
277 m_pen
= g_oglBlackPen
;
278 m_brush
= wxWHITE_BRUSH
;
279 m_font
= g_oglNormalFont
;
280 m_textColour
= wxBLACK
;
281 m_textColourName
= "BLACK";
285 m_attachmentMode
= ATTACHMENT_MODE_NONE
;
286 m_spaceAttachments
= TRUE
;
287 m_disableLabel
= FALSE
;
288 m_fixedWidth
= FALSE
;
289 m_fixedHeight
= FALSE
;
290 m_drawHandles
= TRUE
;
291 m_sensitivity
= OP_ALL
;
294 m_formatMode
= FORMAT_CENTRE_HORIZ
| FORMAT_CENTRE_VERT
;
295 m_shadowMode
= SHADOW_NONE
;
296 m_shadowOffsetX
= 6.0;
297 m_shadowOffsetY
= 6.0;
298 m_shadowBrush
= wxBLACK_BRUSH
;
302 m_centreResize
= TRUE
;
303 m_maintainAspectRatio
= FALSE
;
304 m_highlighted
= FALSE
;
306 m_branchNeckLength
= 10;
307 m_branchStemLength
= 10;
308 m_branchSpacing
= 10;
309 m_branchStyle
= BRANCHING_ATTACHMENT_NORMAL
;
311 // Set up a default region. Much of the above will be put into
312 // the region eventually (the duplication is for compatibility)
313 wxShapeRegion
*region
= new wxShapeRegion
;
314 m_regions
.Append(region
);
315 region
->SetName("0");
316 region
->SetFont(g_oglNormalFont
);
317 region
->SetFormatMode(FORMAT_CENTRE_HORIZ
| FORMAT_CENTRE_VERT
);
318 region
->SetColour("BLACK");
324 m_parent
->GetChildren().DeleteObject(this);
331 m_canvas
->RemoveShape(this);
333 GetEventHandler()->OnDelete();
336 void wxShape::SetHighlight(bool hi
, bool recurse
)
341 wxNode
*node
= m_children
.First();
344 wxShape
*child
= (wxShape
*)node
->Data();
345 child
->SetHighlight(hi
, recurse
);
351 void wxShape::SetSensitivityFilter(int sens
, bool recursive
)
353 if (sens
& OP_DRAG_LEFT
)
358 m_sensitivity
= sens
;
361 wxNode
*node
= m_children
.First();
364 wxShape
*obj
= (wxShape
*)node
->Data();
365 obj
->SetSensitivityFilter(sens
, TRUE
);
371 void wxShape::SetDraggable(bool drag
, bool recursive
)
375 m_sensitivity
|= OP_DRAG_LEFT
;
377 if (m_sensitivity
& OP_DRAG_LEFT
)
378 m_sensitivity
= m_sensitivity
- OP_DRAG_LEFT
;
382 wxNode
*node
= m_children
.First();
385 wxShape
*obj
= (wxShape
*)node
->Data();
386 obj
->SetDraggable(drag
, TRUE
);
392 void wxShape::SetDrawHandles(bool drawH
)
394 m_drawHandles
= drawH
;
395 wxNode
*node
= m_children
.First();
398 wxShape
*obj
= (wxShape
*)node
->Data();
399 obj
->SetDrawHandles(drawH
);
404 void wxShape::SetShadowMode(int mode
, bool redraw
)
406 if (redraw
&& GetCanvas())
408 wxClientDC
dc(GetCanvas());
409 GetCanvas()->PrepareDC(dc
);
422 void wxShape::SetCanvas(wxShapeCanvas
*theCanvas
)
424 m_canvas
= theCanvas
;
425 wxNode
*node
= m_children
.First();
428 wxShape
*child
= (wxShape
*)node
->Data();
429 child
->SetCanvas(theCanvas
);
434 void wxShape::AddToCanvas(wxShapeCanvas
*theCanvas
, wxShape
*addAfter
)
436 theCanvas
->AddShape(this, addAfter
);
437 wxNode
*node
= m_children
.First();
438 wxShape
*lastImage
= this;
441 wxShape
*object
= (wxShape
*)node
->Data();
442 object
->AddToCanvas(theCanvas
, lastImage
);
449 // Insert at front of canvas
450 void wxShape::InsertInCanvas(wxShapeCanvas
*theCanvas
)
452 theCanvas
->InsertShape(this);
453 wxNode
*node
= m_children
.First();
454 wxShape
*lastImage
= this;
457 wxShape
*object
= (wxShape
*)node
->Data();
458 object
->AddToCanvas(theCanvas
, lastImage
);
465 void wxShape::RemoveFromCanvas(wxShapeCanvas
*theCanvas
)
469 theCanvas
->RemoveShape(this);
470 wxNode
*node
= m_children
.First();
473 wxShape
*object
= (wxShape
*)node
->Data();
474 object
->RemoveFromCanvas(theCanvas
);
480 void wxShape::ClearAttachments()
482 wxNode
*node
= m_attachmentPoints
.First();
485 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
489 m_attachmentPoints
.Clear();
492 void wxShape::ClearText(int regionId
)
496 m_text
.DeleteContents(TRUE
);
498 m_text
.DeleteContents(FALSE
);
500 wxNode
*node
= m_regions
.Nth(regionId
);
503 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
507 void wxShape::ClearRegions()
509 wxNode
*node
= m_regions
.First();
512 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
513 wxNode
*next
= node
->Next();
520 void wxShape::AddRegion(wxShapeRegion
*region
)
522 m_regions
.Append(region
);
525 void wxShape::SetDefaultRegionSize()
527 wxNode
*node
= m_regions
.First();
529 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
531 GetBoundingBoxMin(&w
, &h
);
532 region
->SetSize(w
, h
);
535 bool wxShape::HitTest(double x
, double y
, int *attachment
, double *distance
)
540 double width
= 0.0, height
= 0.0;
541 GetBoundingBoxMin(&width
, &height
);
542 if (fabs(width
) < 4.0) width
= 4.0;
543 if (fabs(height
) < 4.0) height
= 4.0;
545 width
+= (double)4.0; height
+= (double)4.0; // Allowance for inaccurate mousing
547 double left
= (double)(m_xpos
- (width
/2.0));
548 double top
= (double)(m_ypos
- (height
/2.0));
549 double right
= (double)(m_xpos
+ (width
/2.0));
550 double bottom
= (double)(m_ypos
+ (height
/2.0));
552 int nearest_attachment
= 0;
554 // If within the bounding box, check the attachment points
555 // within the object.
557 if (x
>= left
&& x
<= right
&& y
>= top
&& y
<= bottom
)
559 int n
= GetNumberOfAttachments();
560 double nearest
= 999999.0;
562 // GetAttachmentPosition[Edge] takes a logical attachment position,
563 // i.e. if it's rotated through 90%, position 0 is East-facing.
565 for (int i
= 0; i
< n
; i
++)
568 if (GetAttachmentPositionEdge(i
, &xp
, &yp
))
570 double l
= (double)sqrt(((xp
- x
) * (xp
- x
)) +
571 ((yp
- y
) * (yp
- y
)));
576 nearest_attachment
= i
;
580 *attachment
= nearest_attachment
;
587 // Format a text string according to the region size, adding
588 // strings with positions to region text list
590 static bool GraphicsInSizeToContents
= FALSE
; // Infinite recursion elimination
591 void wxShape::FormatText(wxDC
& dc
, const wxString
& s
, int i
)
596 if (m_regions
.Number() < 1)
598 wxNode
*node
= m_regions
.Nth(i
);
602 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
604 dc
.SetFont(region
->GetFont());
606 region
->GetSize(&w
, &h
);
608 wxStringList
*stringList
= oglFormatText(dc
, s
, (w
-5), (h
-5), region
->GetFormatMode());
609 node
= stringList
->First();
612 char *s
= (char *)node
->Data();
613 wxShapeTextLine
*line
= new wxShapeTextLine(0.0, 0.0, s
);
614 region
->GetFormattedText().Append((wxObject
*)line
);
620 // Don't try to resize an object with more than one image (this case should be dealt
621 // with by overriden handlers)
622 if ((region
->GetFormatMode() & FORMAT_SIZE_TO_CONTENTS
) &&
623 (region
->GetFormattedText().Number() > 0) &&
624 (m_regions
.Number() == 1) && !GraphicsInSizeToContents
)
626 oglGetCentredTextExtent(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, w
, h
, &actualW
, &actualH
);
627 if ((actualW
+m_textMarginX
!= w
) || (actualH
+m_textMarginY
!= h
))
629 // If we are a descendant of a composite, must make sure the composite gets
631 wxShape
*topAncestor
= GetTopAncestor();
633 if (topAncestor
!= this)
635 // Make sure we don't recurse infinitely
636 GraphicsInSizeToContents
= TRUE
;
638 wxCompositeShape
*composite
= (wxCompositeShape
*)topAncestor
;
639 composite
->Erase(dc
);
640 SetSize(actualW
+m_textMarginX
, actualH
+m_textMarginY
);
641 Move(dc
, m_xpos
, m_ypos
);
642 composite
->CalculateSize();
643 if (composite
->Selected())
645 composite
->DeleteControlPoints(& dc
);
646 composite
->MakeControlPoints();
647 composite
->MakeMandatoryControlPoints();
649 // Where infinite recursion might happen if we didn't stop it
652 GraphicsInSizeToContents
= FALSE
;
657 SetSize(actualW
+m_textMarginX
, actualH
+m_textMarginY
);
658 Move(dc
, m_xpos
, m_ypos
);
660 SetSize(actualW
+m_textMarginX
, actualH
+m_textMarginY
);
661 Move(dc
, m_xpos
, m_ypos
);
665 oglCentreText(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, actualW
, actualH
, region
->GetFormatMode());
669 void wxShape::Recentre(wxDC
& dc
)
672 GetBoundingBoxMin(&w
, &h
);
674 int noRegions
= m_regions
.Number();
675 for (int i
= 0; i
< noRegions
; i
++)
677 wxNode
*node
= m_regions
.Nth(i
);
680 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
681 oglCentreText(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, w
, h
, region
->GetFormatMode());
686 bool wxShape::GetPerimeterPoint(double x1
, double y1
,
687 double x2
, double y2
,
688 double *x3
, double *y3
)
693 void wxShape::SetPen(wxPen
*the_pen
)
698 void wxShape::SetBrush(wxBrush
*the_brush
)
703 // Get the top-most (non-division) ancestor, or self
704 wxShape
*wxShape::GetTopAncestor()
709 if (GetParent()->IsKindOf(CLASSINFO(wxDivisionShape
)))
711 else return GetParent()->GetTopAncestor();
718 void wxShape::SetFont(wxFont
*the_font
, int regionId
)
721 wxNode
*node
= m_regions
.Nth(regionId
);
724 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
725 region
->SetFont(the_font
);
728 wxFont
*wxShape::GetFont(int n
) const
730 wxNode
*node
= m_regions
.Nth(n
);
733 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
734 return region
->GetFont();
737 void wxShape::SetFormatMode(int mode
, int regionId
)
739 wxNode
*node
= m_regions
.Nth(regionId
);
742 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
743 region
->SetFormatMode(mode
);
746 int wxShape::GetFormatMode(int regionId
) const
748 wxNode
*node
= m_regions
.Nth(regionId
);
751 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
752 return region
->GetFormatMode();
755 void wxShape::SetTextColour(const wxString
& the_colour
, int regionId
)
757 wxColour
*wxcolour
= wxTheColourDatabase
->FindColour(the_colour
);
758 m_textColour
= wxcolour
;
759 m_textColourName
= the_colour
;
761 wxNode
*node
= m_regions
.Nth(regionId
);
764 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
765 region
->SetColour(the_colour
);
768 wxString
wxShape::GetTextColour(int regionId
) const
770 wxNode
*node
= m_regions
.Nth(regionId
);
773 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
774 return region
->GetColour();
777 void wxShape::SetRegionName(const wxString
& name
, int regionId
)
779 wxNode
*node
= m_regions
.Nth(regionId
);
782 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
783 region
->SetName(name
);
786 wxString
wxShape::GetRegionName(int regionId
)
788 wxNode
*node
= m_regions
.Nth(regionId
);
791 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
792 return region
->GetName();
795 int wxShape::GetRegionId(const wxString
& name
)
797 wxNode
*node
= m_regions
.First();
801 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
802 if (region
->GetName() == name
)
810 // Name all m_regions in all subimages recursively.
811 void wxShape::NameRegions(const wxString
& parentName
)
813 int n
= GetNumberOfTextRegions();
815 for (int i
= 0; i
< n
; i
++)
817 if (parentName
.Length() > 0)
818 sprintf(buf
, "%s.%d", (const char*) parentName
, i
);
820 sprintf(buf
, "%d", i
);
821 SetRegionName(buf
, i
);
823 wxNode
*node
= m_children
.First();
827 wxShape
*child
= (wxShape
*)node
->Data();
828 if (parentName
.Length() > 0)
829 sprintf(buf
, "%s.%d", (const char*) parentName
, j
);
831 sprintf(buf
, "%d", j
);
832 child
->NameRegions(buf
);
838 // Get a region by name, possibly looking recursively into composites.
839 wxShape
*wxShape::FindRegion(const wxString
& name
, int *regionId
)
841 int id
= GetRegionId(name
);
848 wxNode
*node
= m_children
.First();
851 wxShape
*child
= (wxShape
*)node
->Data();
852 wxShape
*actualImage
= child
->FindRegion(name
, regionId
);
860 // Finds all region names for this image (composite or simple).
861 // Supply empty string list.
862 void wxShape::FindRegionNames(wxStringList
& list
)
864 int n
= GetNumberOfTextRegions();
865 for (int i
= 0; i
< n
; i
++)
867 wxString
name(GetRegionName(i
));
868 list
.Add((const char*) name
);
871 wxNode
*node
= m_children
.First();
874 wxShape
*child
= (wxShape
*)node
->Data();
875 child
->FindRegionNames(list
);
880 void wxShape::AssignNewIds()
884 wxNode
*node
= m_children
.First();
887 wxShape
*child
= (wxShape
*)node
->Data();
888 child
->AssignNewIds();
893 void wxShape::OnDraw(wxDC
& dc
)
897 void wxShape::OnMoveLinks(wxDC
& dc
)
899 // Want to set the ends of all attached links
900 // to point to/from this object
902 wxNode
*current
= m_lines
.First();
905 wxLineShape
*line
= (wxLineShape
*)current
->Data();
906 line
->GetEventHandler()->OnMoveLink(dc
);
907 current
= current
->Next();
912 void wxShape::OnDrawContents(wxDC
& dc
)
914 double bound_x
, bound_y
;
915 GetBoundingBoxMin(&bound_x
, &bound_y
);
916 if (m_regions
.Number() < 1) return;
918 if (m_pen
) dc
.SetPen(m_pen
);
920 wxShapeRegion
*region
= (wxShapeRegion
*)m_regions
.First()->Data();
921 if (region
->GetFont()) dc
.SetFont(region
->GetFont());
923 dc
.SetTextForeground(* (region
->GetActualColourObject()));
924 dc
.SetBackgroundMode(wxTRANSPARENT
);
927 oglCentreText(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, bound_x
, bound_y
, region
->GetFormatMode());
930 if (!GetDisableLabel())
932 oglDrawFormattedText(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, bound_x
, bound_y
, region
->GetFormatMode());
936 void wxShape::DrawContents(wxDC
& dc
)
938 GetEventHandler()->OnDrawContents(dc
);
941 void wxShape::OnSize(double x
, double y
)
945 bool wxShape::OnMovePre(wxDC
& dc
, double x
, double y
, double old_x
, double old_y
, bool display
)
950 void wxShape::OnMovePost(wxDC
& dc
, double x
, double y
, double old_x
, double old_y
, bool display
)
954 void wxShape::OnErase(wxDC
& dc
)
960 wxNode
*current
= m_lines
.First();
963 wxLineShape
*line
= (wxLineShape
*)current
->Data();
964 line
->GetEventHandler()->OnErase(dc
);
965 current
= current
->Next();
967 GetEventHandler()->OnEraseContents(dc
);
970 void wxShape::OnEraseContents(wxDC
& dc
)
975 double maxX
, maxY
, minX
, minY
;
978 GetBoundingBoxMin(&minX
, &minY
);
979 GetBoundingBoxMax(&maxX
, &maxY
);
980 double topLeftX
= (double)(xp
- (maxX
/ 2.0) - 2.0);
981 double topLeftY
= (double)(yp
- (maxY
/ 2.0) - 2.0);
985 penWidth
= m_pen
->GetWidth();
987 dc
.SetPen(g_oglWhiteBackgroundPen
);
988 dc
.SetBrush(g_oglWhiteBackgroundBrush
);
989 dc
.DrawRectangle(WXROUND(topLeftX
- penWidth
), WXROUND(topLeftY
- penWidth
),
990 WXROUND(maxX
+ penWidth
*2.0 + 4.0), WXROUND(maxY
+ penWidth
*2.0 + 4.0));
993 void wxShape::EraseLinks(wxDC
& dc
, int attachment
, bool recurse
)
998 wxNode
*current
= m_lines
.First();
1001 wxLineShape
*line
= (wxLineShape
*)current
->Data();
1002 if (attachment
== -1 || ((line
->GetTo() == this && line
->GetAttachmentTo() == attachment
) ||
1003 (line
->GetFrom() == this && line
->GetAttachmentFrom() == attachment
)))
1004 line
->GetEventHandler()->OnErase(dc
);
1005 current
= current
->Next();
1009 wxNode
*node
= m_children
.First();
1012 wxShape
*child
= (wxShape
*)node
->Data();
1013 child
->EraseLinks(dc
, attachment
, recurse
);
1014 node
= node
->Next();
1019 void wxShape::DrawLinks(wxDC
& dc
, int attachment
, bool recurse
)
1024 wxNode
*current
= m_lines
.First();
1027 wxLineShape
*line
= (wxLineShape
*)current
->Data();
1028 if (attachment
== -1 ||
1029 (line
->GetTo() == this && line
->GetAttachmentTo() == attachment
) ||
1030 (line
->GetFrom() == this && line
->GetAttachmentFrom() == attachment
))
1032 current
= current
->Next();
1036 wxNode
*node
= m_children
.First();
1039 wxShape
*child
= (wxShape
*)node
->Data();
1040 child
->DrawLinks(dc
, attachment
, recurse
);
1041 node
= node
->Next();
1046 // Returns TRUE if pt1 <= pt2 in the sense that one point comes before another on an
1047 // edge of the shape.
1048 // attachmentPoint is the attachment point (= side) in question.
1050 // This is the default, rectangular implementation.
1051 bool wxShape::AttachmentSortTest(int attachmentPoint
, const wxRealPoint
& pt1
, const wxRealPoint
& pt2
)
1053 int physicalAttachment
= LogicalToPhysicalAttachment(attachmentPoint
);
1054 switch (physicalAttachment
)
1059 return (pt1
.x
<= pt2
.x
) ;
1065 return (pt1
.y
<= pt2
.y
) ;
1073 bool wxShape::MoveLineToNewAttachment(wxDC
& dc
, wxLineShape
*to_move
,
1076 if (GetAttachmentMode() == ATTACHMENT_MODE_NONE
)
1079 int newAttachment
, oldAttachment
;
1082 // Is (x, y) on this object? If so, find the new attachment point
1083 // the user has moved the point to
1084 bool hit
= HitTest(x
, y
, &newAttachment
, &distance
);
1090 if (to_move
->GetTo() == this)
1091 oldAttachment
= to_move
->GetAttachmentTo();
1093 oldAttachment
= to_move
->GetAttachmentFrom();
1095 // The links in a new ordering.
1098 // First, add all links to the new list.
1099 wxNode
*node
= m_lines
.First();
1102 newOrdering
.Append(node
->Data());
1103 node
= node
->Next();
1106 // Delete the line object from the list of links; we're going to move
1107 // it to another position in the list
1108 newOrdering
.DeleteObject(to_move
);
1110 double old_x
= (double) -99999.9;
1111 double old_y
= (double) -99999.9;
1113 node
= newOrdering
.First();
1116 while (!found
&& node
)
1118 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1119 if ((line
->GetTo() == this && oldAttachment
== line
->GetAttachmentTo()) ||
1120 (line
->GetFrom() == this && oldAttachment
== line
->GetAttachmentFrom()))
1122 double startX
, startY
, endX
, endY
;
1124 line
->GetEnds(&startX
, &startY
, &endX
, &endY
);
1125 if (line
->GetTo() == this)
1135 wxRealPoint
thisPoint(xp
, yp
);
1136 wxRealPoint
lastPoint(old_x
, old_y
);
1137 wxRealPoint
newPoint(x
, y
);
1139 if (AttachmentSortTest(newAttachment
, newPoint
, thisPoint
) && AttachmentSortTest(newAttachment
, lastPoint
, newPoint
))
1142 newOrdering
.Insert(node
, to_move
);
1148 node
= node
->Next();
1152 newOrdering
.Append(to_move
);
1154 GetEventHandler()->OnChangeAttachment(newAttachment
, to_move
, newOrdering
);
1159 void wxShape::OnChangeAttachment(int attachment
, wxLineShape
* line
, wxList
& ordering
)
1161 if (line
->GetTo() == this)
1162 line
->SetAttachmentTo(attachment
);
1164 line
->SetAttachmentFrom(attachment
);
1166 ApplyAttachmentOrdering(ordering
);
1168 wxClientDC
dc(GetCanvas());
1169 GetCanvas()->PrepareDC(dc
);
1173 if (!GetCanvas()->GetQuickEditMode()) GetCanvas()->Redraw(dc
);
1176 // Reorders the lines according to the given list.
1177 void wxShape::ApplyAttachmentOrdering(wxList
& linesToSort
)
1179 // This is a temporary store of all the lines.
1182 wxNode
*node
= m_lines
.First();
1185 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1186 linesStore
.Append(line
);
1187 node
= node
->Next();;
1192 node
= linesToSort
.First();
1195 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1196 if (linesStore
.Member(line
))
1199 linesStore
.DeleteObject(line
);
1200 m_lines
.Append(line
);
1202 node
= node
->Next();
1205 // Now add any lines that haven't been listed in linesToSort.
1206 node
= linesStore
.First();
1209 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1210 m_lines
.Append(line
);
1211 node
= node
->Next();
1215 // Reorders the lines coming into the node image at this attachment
1216 // position, in the order in which they appear in linesToSort.
1217 // Any remaining lines not in the list will be added to the end.
1218 void wxShape::SortLines(int attachment
, wxList
& linesToSort
)
1220 // This is a temporary store of all the lines at this attachment
1221 // point. We'll tick them off as we've processed them.
1222 wxList linesAtThisAttachment
;
1224 wxNode
*node
= m_lines
.First();
1227 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1228 wxNode
*next
= node
->Next();
1229 if ((line
->GetTo() == this && line
->GetAttachmentTo() == attachment
) ||
1230 (line
->GetFrom() == this && line
->GetAttachmentFrom() == attachment
))
1232 linesAtThisAttachment
.Append(line
);
1236 else node
= node
->Next();
1239 node
= linesToSort
.First();
1242 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1243 if (linesAtThisAttachment
.Member(line
))
1246 linesAtThisAttachment
.DeleteObject(line
);
1247 m_lines
.Append(line
);
1249 node
= node
->Next();
1252 // Now add any lines that haven't been listed in linesToSort.
1253 node
= linesAtThisAttachment
.First();
1256 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1257 m_lines
.Append(line
);
1258 node
= node
->Next();
1262 void wxShape::OnHighlight(wxDC
& dc
)
1266 void wxShape::OnLeftClick(double x
, double y
, int keys
, int attachment
)
1268 if ((m_sensitivity
& OP_CLICK_LEFT
) != OP_CLICK_LEFT
)
1274 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1275 m_parent
->GetEventHandler()->OnLeftClick(x
, y
, keys
, attachment
);
1281 void wxShape::OnRightClick(double x
, double y
, int keys
, int attachment
)
1283 if ((m_sensitivity
& OP_CLICK_RIGHT
) != OP_CLICK_RIGHT
)
1289 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1290 m_parent
->GetEventHandler()->OnRightClick(x
, y
, keys
, attachment
);
1296 double DragOffsetX
= 0.0;
1297 double DragOffsetY
= 0.0;
1299 void wxShape::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
1301 if ((m_sensitivity
& OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
1307 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1308 m_parent
->GetEventHandler()->OnDragLeft(draw
, x
, y
, keys
, attachment
);
1313 wxClientDC
dc(GetCanvas());
1314 GetCanvas()->PrepareDC(dc
);
1316 dc
.SetLogicalFunction(wxXOR
);
1318 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1319 dc
.SetPen(dottedPen
);
1320 dc
.SetBrush(* wxTRANSPARENT_BRUSH
);
1323 xx
= x
+ DragOffsetX
;
1324 yy
= y
+ DragOffsetY
;
1326 m_canvas
->Snap(&xx
, &yy
);
1327 // m_xpos = xx; m_ypos = yy;
1329 GetBoundingBoxMax(&w
, &h
);
1330 GetEventHandler()->OnDrawOutline(dc
, xx
, yy
, w
, h
);
1333 void wxShape::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
1335 if ((m_sensitivity
& OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
1341 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1342 m_parent
->GetEventHandler()->OnBeginDragLeft(x
, y
, keys
, attachment
);
1347 DragOffsetX
= m_xpos
- x
;
1348 DragOffsetY
= m_ypos
- y
;
1350 wxClientDC
dc(GetCanvas());
1351 GetCanvas()->PrepareDC(dc
);
1353 // New policy: don't erase shape until end of drag.
1357 xx
= x
+ DragOffsetX
;
1358 yy
= y
+ DragOffsetY
;
1359 m_canvas
->Snap(&xx
, &yy
);
1360 // m_xpos = xx; m_ypos = yy;
1361 dc
.SetLogicalFunction(wxXOR
);
1363 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1364 dc
.SetPen(dottedPen
);
1365 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1368 GetBoundingBoxMax(&w
, &h
);
1369 GetEventHandler()->OnDrawOutline(dc
, xx
, yy
, w
, h
);
1370 m_canvas
->CaptureMouse();
1373 void wxShape::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
1375 m_canvas
->ReleaseMouse();
1376 if ((m_sensitivity
& OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
1382 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1383 m_parent
->GetEventHandler()->OnEndDragLeft(x
, y
, keys
, attachment
);
1388 wxClientDC
dc(GetCanvas());
1389 GetCanvas()->PrepareDC(dc
);
1391 dc
.SetLogicalFunction(wxCOPY
);
1393 double xx
= x
+ DragOffsetX
;
1394 double yy
= y
+ DragOffsetY
;
1395 m_canvas
->Snap(&xx
, &yy
);
1396 // canvas->Snap(&m_xpos, &m_ypos);
1398 // New policy: erase shape at end of drag.
1402 if (m_canvas
&& !m_canvas
->GetQuickEditMode()) m_canvas
->Redraw(dc
);
1405 void wxShape::OnDragRight(bool draw
, double x
, double y
, int keys
, int attachment
)
1407 if ((m_sensitivity
& OP_DRAG_RIGHT
) != OP_DRAG_RIGHT
)
1413 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1414 m_parent
->GetEventHandler()->OnDragRight(draw
, x
, y
, keys
, attachment
);
1420 void wxShape::OnBeginDragRight(double x
, double y
, int keys
, int attachment
)
1422 if ((m_sensitivity
& OP_DRAG_RIGHT
) != OP_DRAG_RIGHT
)
1428 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1429 m_parent
->GetEventHandler()->OnBeginDragRight(x
, y
, keys
, attachment
);
1435 void wxShape::OnEndDragRight(double x
, double y
, int keys
, int attachment
)
1437 if ((m_sensitivity
& OP_DRAG_RIGHT
) != OP_DRAG_RIGHT
)
1443 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1444 m_parent
->GetEventHandler()->OnEndDragRight(x
, y
, keys
, attachment
);
1450 void wxShape::OnDrawOutline(wxDC
& dc
, double x
, double y
, double w
, double h
)
1452 double top_left_x
= (double)(x
- w
/2.0);
1453 double top_left_y
= (double)(y
- h
/2.0);
1454 double top_right_x
= (double)(top_left_x
+ w
);
1455 double top_right_y
= (double)top_left_y
;
1456 double bottom_left_x
= (double)top_left_x
;
1457 double bottom_left_y
= (double)(top_left_y
+ h
);
1458 double bottom_right_x
= (double)top_right_x
;
1459 double bottom_right_y
= (double)bottom_left_y
;
1462 points
[0].x
= WXROUND(top_left_x
); points
[0].y
= WXROUND(top_left_y
);
1463 points
[1].x
= WXROUND(top_right_x
); points
[1].y
= WXROUND(top_right_y
);
1464 points
[2].x
= WXROUND(bottom_right_x
); points
[2].y
= WXROUND(bottom_right_y
);
1465 points
[3].x
= WXROUND(bottom_left_x
); points
[3].y
= WXROUND(bottom_left_y
);
1466 points
[4].x
= WXROUND(top_left_x
); points
[4].y
= WXROUND(top_left_y
);
1468 dc
.DrawLines(5, points
);
1471 void wxShape::Attach(wxShapeCanvas
*can
)
1476 void wxShape::Detach()
1481 void wxShape::Move(wxDC
& dc
, double x
, double y
, bool display
)
1483 double old_x
= m_xpos
;
1484 double old_y
= m_ypos
;
1486 if (!GetEventHandler()->OnMovePre(dc
, x
, y
, old_x
, old_y
, display
))
1493 m_xpos
= x
; m_ypos
= y
;
1495 ResetControlPoints();
1502 GetEventHandler()->OnMovePost(dc
, x
, y
, old_x
, old_y
, display
);
1505 void wxShape::MoveLinks(wxDC
& dc
)
1507 GetEventHandler()->OnMoveLinks(dc
);
1511 void wxShape::Draw(wxDC
& dc
)
1515 GetEventHandler()->OnDraw(dc
);
1516 GetEventHandler()->OnDrawContents(dc
);
1517 GetEventHandler()->OnDrawControlPoints(dc
);
1518 GetEventHandler()->OnDrawBranches(dc
);
1522 void wxShape::Flash()
1526 wxClientDC
dc(GetCanvas());
1527 GetCanvas()->PrepareDC(dc
);
1529 dc
.SetLogicalFunction(wxXOR
);
1531 dc
.SetLogicalFunction(wxCOPY
);
1536 void wxShape::Show(bool show
)
1539 wxNode
*node
= m_children
.First();
1542 wxShape
*image
= (wxShape
*)node
->Data();
1544 node
= node
->Next();
1548 void wxShape::Erase(wxDC
& dc
)
1550 GetEventHandler()->OnErase(dc
);
1551 GetEventHandler()->OnEraseControlPoints(dc
);
1552 GetEventHandler()->OnDrawBranches(dc
, TRUE
);
1555 void wxShape::EraseContents(wxDC
& dc
)
1557 GetEventHandler()->OnEraseContents(dc
);
1560 void wxShape::AddText(const wxString
& string
)
1562 wxNode
*node
= m_regions
.First();
1565 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
1566 region
->ClearText();
1567 wxShapeTextLine
*new_line
=
1568 new wxShapeTextLine(0.0, 0.0, string
);
1569 region
->GetFormattedText().Append(new_line
);
1571 m_formatted
= FALSE
;
1574 void wxShape::SetSize(double x
, double y
, bool recursive
)
1576 SetAttachmentSize(x
, y
);
1577 SetDefaultRegionSize();
1580 void wxShape::SetAttachmentSize(double w
, double h
)
1584 double width
, height
;
1585 GetBoundingBoxMin(&width
, &height
);
1588 else scaleX
= w
/width
;
1591 else scaleY
= h
/height
;
1593 wxNode
*node
= m_attachmentPoints
.First();
1596 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
1597 point
->m_x
= (double)(point
->m_x
* scaleX
);
1598 point
->m_y
= (double)(point
->m_y
* scaleY
);
1599 node
= node
->Next();
1603 // Add line FROM this object
1604 void wxShape::AddLine(wxLineShape
*line
, wxShape
*other
,
1605 int attachFrom
, int attachTo
,
1606 // The line ordering
1607 int positionFrom
, int positionTo
)
1609 if (positionFrom
== -1)
1611 if (!m_lines
.Member(line
))
1612 m_lines
.Append(line
);
1616 // Don't preserve old ordering if we have new ordering instructions
1617 m_lines
.DeleteObject(line
);
1618 if (positionFrom
< m_lines
.Number())
1620 wxNode
* node
= m_lines
.Nth(positionFrom
);
1621 m_lines
.Insert(node
, line
);
1624 m_lines
.Append(line
);
1627 if (positionTo
== -1)
1629 if (!other
->m_lines
.Member(line
))
1630 other
->m_lines
.Append(line
);
1634 // Don't preserve old ordering if we have new ordering instructions
1635 other
->m_lines
.DeleteObject(line
);
1636 if (positionTo
< other
->m_lines
.Number())
1638 wxNode
* node
= other
->m_lines
.Nth(positionTo
);
1639 other
->m_lines
.Insert(node
, line
);
1642 other
->m_lines
.Append(line
);
1645 // Wrong: doesn't preserve ordering of shape already linked
1646 m_lines
.DeleteObject(line
);
1647 other
->m_lines
.DeleteObject(line
);
1649 if (positionFrom
== -1)
1650 m_lines
.Append(line
);
1653 if (positionFrom
< m_lines
.Number())
1655 wxNode
* node
= m_lines
.Nth(positionFrom
);
1656 m_lines
.Insert(node
, line
);
1659 m_lines
.Append(line
);
1662 if (positionTo
== -1)
1663 other
->m_lines
.Append(line
);
1666 if (positionTo
< other
->m_lines
.Number())
1668 wxNode
* node
= other
->m_lines
.Nth(positionTo
);
1669 other
->m_lines
.Insert(node
, line
);
1672 other
->m_lines
.Append(line
);
1676 line
->SetFrom(this);
1678 line
->SetAttachments(attachFrom
, attachTo
);
1681 void wxShape::RemoveLine(wxLineShape
*line
)
1683 if (line
->GetFrom() == this)
1684 line
->GetTo()->m_lines
.DeleteObject(line
);
1686 line
->GetFrom()->m_lines
.DeleteObject(line
);
1688 m_lines
.DeleteObject(line
);
1692 void wxShape::WriteAttributes(wxExpr
*clause
)
1694 clause
->AddAttributeValueString("type", GetClassInfo()->GetClassName());
1695 clause
->AddAttributeValue("id", m_id
);
1699 int penWidth
= m_pen
->GetWidth();
1700 int penStyle
= m_pen
->GetStyle();
1702 clause
->AddAttributeValue("pen_width", (long)penWidth
);
1703 if (penStyle
!= wxSOLID
)
1704 clause
->AddAttributeValue("pen_style", (long)penStyle
);
1706 wxString penColour
= wxTheColourDatabase
->FindName(m_pen
->GetColour());
1707 if (penColour
== "")
1709 wxString
hex(oglColourToHex(m_pen
->GetColour()));
1710 hex
= wxString("#") + hex
;
1711 clause
->AddAttributeValueString("pen_colour", hex
);
1713 else if (penColour
!= "BLACK")
1714 clause
->AddAttributeValueString("pen_colour", penColour
);
1719 wxString brushColour
= wxTheColourDatabase
->FindName(m_brush
->GetColour());
1721 if (brushColour
== "")
1723 wxString
hex(oglColourToHex(m_brush
->GetColour()));
1724 hex
= wxString("#") + hex
;
1725 clause
->AddAttributeValueString("brush_colour", hex
);
1727 else if (brushColour
!= "WHITE")
1728 clause
->AddAttributeValueString("brush_colour", brushColour
);
1730 if (m_brush
->GetStyle() != wxSOLID
)
1731 clause
->AddAttributeValue("brush_style", (long)m_brush
->GetStyle());
1736 int n_lines
= m_lines
.Number();
1739 wxExpr
*list
= new wxExpr(wxExprList
);
1740 wxNode
*node
= m_lines
.First();
1743 wxShape
*line
= (wxShape
*)node
->Data();
1744 wxExpr
*id_expr
= new wxExpr(line
->GetId());
1745 list
->Append(id_expr
);
1746 node
= node
->Next();
1748 clause
->AddAttributeValue("arcs", list
);
1751 // Miscellaneous members
1752 if (m_attachmentMode
!= 0)
1753 clause
->AddAttributeValue("use_attachments", (long)m_attachmentMode
);
1754 if (m_sensitivity
!= OP_ALL
)
1755 clause
->AddAttributeValue("sensitivity", (long)m_sensitivity
);
1756 if (!m_spaceAttachments
)
1757 clause
->AddAttributeValue("space_attachments", (long)m_spaceAttachments
);
1759 clause
->AddAttributeValue("fixed_width", (long)m_fixedWidth
);
1761 clause
->AddAttributeValue("fixed_height", (long)m_fixedHeight
);
1762 if (m_shadowMode
!= SHADOW_NONE
)
1763 clause
->AddAttributeValue("shadow_mode", (long)m_shadowMode
);
1764 if (m_centreResize
!= TRUE
)
1765 clause
->AddAttributeValue("centre_resize", (long)0);
1766 clause
->AddAttributeValue("maintain_aspect_ratio", (long) m_maintainAspectRatio
);
1767 if (m_highlighted
!= FALSE
)
1768 clause
->AddAttributeValue("hilite", (long)m_highlighted
);
1770 if (m_parent
) // For composite objects
1771 clause
->AddAttributeValue("parent", (long)m_parent
->GetId());
1773 if (m_rotation
!= 0.0)
1774 clause
->AddAttributeValue("rotation", m_rotation
);
1776 if (!this->IsKindOf(CLASSINFO(wxLineShape
)))
1778 clause
->AddAttributeValue("neck_length", (long) m_branchNeckLength
);
1779 clause
->AddAttributeValue("stem_length", (long) m_branchStemLength
);
1780 clause
->AddAttributeValue("branch_spacing", (long) m_branchSpacing
);
1781 clause
->AddAttributeValue("branch_style", (long) m_branchStyle
);
1784 // Write user-defined attachment points, if any
1785 if (m_attachmentPoints
.Number() > 0)
1787 wxExpr
*attachmentList
= new wxExpr(wxExprList
);
1788 wxNode
*node
= m_attachmentPoints
.First();
1791 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
1792 wxExpr
*pointExpr
= new wxExpr(wxExprList
);
1793 pointExpr
->Append(new wxExpr((long)point
->m_id
));
1794 pointExpr
->Append(new wxExpr(point
->m_x
));
1795 pointExpr
->Append(new wxExpr(point
->m_y
));
1796 attachmentList
->Append(pointExpr
);
1797 node
= node
->Next();
1799 clause
->AddAttributeValue("user_attachments", attachmentList
);
1802 // Write text regions
1803 WriteRegions(clause
);
1806 void wxShape::WriteRegions(wxExpr
*clause
)
1808 // Output regions as region1 = (...), region2 = (...), etc
1809 // and formatted text as text1 = (...), text2 = (...) etc.
1811 char regionNameBuf
[20];
1812 char textNameBuf
[20];
1813 wxNode
*node
= m_regions
.First();
1816 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
1817 sprintf(regionNameBuf
, "region%d", regionNo
);
1818 sprintf(textNameBuf
, "text%d", regionNo
);
1820 // Original text and region attributes:
1821 // region1 = (regionName regionText x y width height minWidth minHeight proportionX proportionY
1822 // formatMode fontSize fontFamily fontStyle fontWeight textColour)
1823 wxExpr
*regionExpr
= new wxExpr(wxExprList
);
1824 regionExpr
->Append(new wxExpr(wxExprString
, (region
->m_regionName
? region
->m_regionName
: "")));
1825 regionExpr
->Append(new wxExpr(wxExprString
, (region
->m_regionText
? region
->m_regionText
: "")));
1827 regionExpr
->Append(new wxExpr(region
->m_x
));
1828 regionExpr
->Append(new wxExpr(region
->m_y
));
1829 regionExpr
->Append(new wxExpr(region
->GetWidth()));
1830 regionExpr
->Append(new wxExpr(region
->GetHeight()));
1832 regionExpr
->Append(new wxExpr(region
->m_minWidth
));
1833 regionExpr
->Append(new wxExpr(region
->m_minHeight
));
1834 regionExpr
->Append(new wxExpr(region
->m_regionProportionX
));
1835 regionExpr
->Append(new wxExpr(region
->m_regionProportionY
));
1837 regionExpr
->Append(new wxExpr((long)region
->m_formatMode
));
1839 regionExpr
->Append(new wxExpr((long)(region
->m_font
? region
->m_font
->GetPointSize() : 10)));
1840 regionExpr
->Append(new wxExpr((long)(region
->m_font
? region
->m_font
->GetFamily() : wxDEFAULT
)));
1841 regionExpr
->Append(new wxExpr((long)(region
->m_font
? region
->m_font
->GetStyle() : wxDEFAULT
)));
1842 regionExpr
->Append(new wxExpr((long)(region
->m_font
? region
->m_font
->GetWeight() : wxNORMAL
)));
1843 regionExpr
->Append(new wxExpr(wxExprString
, region
->m_textColour
? region
->m_textColour
: "BLACK"));
1845 // New members for pen colour/style
1846 regionExpr
->Append(new wxExpr(wxExprString
, region
->m_penColour
? region
->m_penColour
: "BLACK"));
1847 regionExpr
->Append(new wxExpr((long)region
->m_penStyle
));
1850 // text1 = ((x y string) (x y string) ...)
1851 wxExpr
*textExpr
= new wxExpr(wxExprList
);
1853 wxNode
*textNode
= region
->m_formattedText
.First();
1856 wxShapeTextLine
*line
= (wxShapeTextLine
*)textNode
->Data();
1857 wxExpr
*list2
= new wxExpr(wxExprList
);
1858 list2
->Append(new wxExpr(line
->GetX()));
1859 list2
->Append(new wxExpr(line
->GetY()));
1860 list2
->Append(new wxExpr(wxExprString
, line
->GetText()));
1861 textExpr
->Append(list2
);
1862 textNode
= textNode
->Next();
1865 // Now add both attributes to the clause
1866 clause
->AddAttributeValue(regionNameBuf
, regionExpr
);
1867 clause
->AddAttributeValue(textNameBuf
, textExpr
);
1869 node
= node
->Next();
1874 void wxShape::ReadAttributes(wxExpr
*clause
)
1876 clause
->GetAttributeValue("id", m_id
);
1879 clause
->GetAttributeValue("x", m_xpos
);
1880 clause
->GetAttributeValue("y", m_ypos
);
1882 // Input text strings (FOR COMPATIBILITY WITH OLD FILES ONLY. SEE REGION CODE BELOW.)
1884 wxExpr
*strings
= clause
->AttributeValue("text");
1885 if (strings
&& strings
->Type() == wxExprList
)
1887 m_formatted
= TRUE
; // Assume text is formatted unless we prove otherwise
1888 wxExpr
*node
= strings
->value
.first
;
1891 wxExpr
*string_expr
= node
;
1894 wxString
the_string("");
1896 // string_expr can either be a string, or a list of
1897 // 3 elements: x, y, and string.
1898 if (string_expr
->Type() == wxExprString
)
1900 the_string
= string_expr
->StringValue();
1901 m_formatted
= FALSE
;
1903 else if (string_expr
->Type() == wxExprList
)
1905 wxExpr
*first
= string_expr
->value
.first
;
1906 wxExpr
*second
= first
? first
->next
: NULL
;
1907 wxExpr
*third
= second
? second
->next
: NULL
;
1909 if (first
&& second
&& third
&&
1910 (first
->Type() == wxExprReal
|| first
->Type() == wxExprInteger
) &&
1911 (second
->Type() == wxExprReal
|| second
->Type() == wxExprInteger
) &&
1912 third
->Type() == wxExprString
)
1914 if (first
->Type() == wxExprReal
)
1915 the_x
= first
->RealValue();
1916 else the_x
= (double)first
->IntegerValue();
1918 if (second
->Type() == wxExprReal
)
1919 the_y
= second
->RealValue();
1920 else the_y
= (double)second
->IntegerValue();
1922 the_string
= third
->StringValue();
1925 wxShapeTextLine
*line
=
1926 new wxShapeTextLine(the_x
, the_y
, (char*) (const char*) the_string
);
1927 m_text
.Append(line
);
1933 wxString pen_string
= "";
1934 wxString brush_string
= "";
1936 int pen_style
= wxSOLID
;
1937 int brush_style
= wxSOLID
;
1938 m_attachmentMode
= ATTACHMENT_MODE_NONE
;
1940 clause
->GetAttributeValue("pen_colour", pen_string
);
1941 clause
->GetAttributeValue("text_colour", m_textColourName
);
1943 SetTextColour(m_textColourName
);
1945 clause
->GetAttributeValue("region_name", m_regionName
);
1947 clause
->GetAttributeValue("brush_colour", brush_string
);
1948 clause
->GetAttributeValue("pen_width", pen_width
);
1949 clause
->GetAttributeValue("pen_style", pen_style
);
1950 clause
->GetAttributeValue("brush_style", brush_style
);
1952 int iVal
= (int) m_attachmentMode
;
1953 clause
->GetAttributeValue("use_attachments", iVal
);
1954 m_attachmentMode
= iVal
;
1956 clause
->GetAttributeValue("sensitivity", m_sensitivity
);
1958 iVal
= (int) m_spaceAttachments
;
1959 clause
->GetAttributeValue("space_attachments", iVal
);
1960 m_spaceAttachments
= (iVal
!= 0);
1962 iVal
= (int) m_fixedWidth
;
1963 clause
->GetAttributeValue("fixed_width", iVal
);
1964 m_fixedWidth
= (iVal
!= 0);
1966 iVal
= (int) m_fixedHeight
;
1967 clause
->GetAttributeValue("fixed_height", iVal
);
1968 m_fixedHeight
= (iVal
!= 0);
1970 clause
->GetAttributeValue("format_mode", m_formatMode
);
1971 clause
->GetAttributeValue("shadow_mode", m_shadowMode
);
1973 iVal
= m_branchNeckLength
;
1974 clause
->GetAttributeValue("neck_length", iVal
);
1975 m_branchNeckLength
= iVal
;
1977 iVal
= m_branchStemLength
;
1978 clause
->GetAttributeValue("stem_length", iVal
);
1979 m_branchStemLength
= iVal
;
1981 iVal
= m_branchSpacing
;
1982 clause
->GetAttributeValue("branch_spacing", iVal
);
1983 m_branchSpacing
= iVal
;
1985 clause
->GetAttributeValue("branch_style", m_branchStyle
);
1987 iVal
= (int) m_centreResize
;
1988 clause
->GetAttributeValue("centre_resize", iVal
);
1989 m_centreResize
= (iVal
!= 0);
1991 iVal
= (int) m_maintainAspectRatio
;
1992 clause
->GetAttributeValue("maintain_aspect_ratio", iVal
);
1993 m_maintainAspectRatio
= (iVal
!= 0);
1995 iVal
= (int) m_highlighted
;
1996 clause
->GetAttributeValue("hilite", iVal
);
1997 m_highlighted
= (iVal
!= 0);
1999 clause
->GetAttributeValue("rotation", m_rotation
);
2001 if (pen_string
== "")
2002 pen_string
= "BLACK";
2003 if (brush_string
== "")
2004 brush_string
= "WHITE";
2006 if (pen_string
[0] == '#')
2008 wxColour
col(oglHexToColour(pen_string
.After('#')));
2009 m_pen
= wxThePenList
->FindOrCreatePen(col
, pen_width
, pen_style
);
2012 m_pen
= wxThePenList
->FindOrCreatePen(pen_string
, pen_width
, pen_style
);
2015 m_pen
= wxBLACK_PEN
;
2017 if (brush_string
[0] == '#')
2019 wxColour
col(oglHexToColour(brush_string
.After('#')));
2020 m_brush
= wxTheBrushList
->FindOrCreateBrush(col
, brush_style
);
2023 m_brush
= wxTheBrushList
->FindOrCreateBrush(brush_string
, brush_style
);
2026 m_brush
= wxWHITE_BRUSH
;
2028 int point_size
= 10;
2029 clause
->GetAttributeValue("point_size", point_size
);
2030 SetFont(oglMatchFont(point_size
));
2032 // Read user-defined attachment points, if any
2033 wxExpr
*attachmentList
= clause
->AttributeValue("user_attachments");
2036 wxExpr
*pointExpr
= attachmentList
->GetFirst();
2039 wxExpr
*idExpr
= pointExpr
->Nth(0);
2040 wxExpr
*xExpr
= pointExpr
->Nth(1);
2041 wxExpr
*yExpr
= pointExpr
->Nth(2);
2042 if (idExpr
&& xExpr
&& yExpr
)
2044 wxAttachmentPoint
*point
= new wxAttachmentPoint
;
2045 point
->m_id
= (int)idExpr
->IntegerValue();
2046 point
->m_x
= xExpr
->RealValue();
2047 point
->m_y
= yExpr
->RealValue();
2048 m_attachmentPoints
.Append((wxObject
*)point
);
2050 pointExpr
= pointExpr
->GetNext();
2054 // Read text regions
2055 ReadRegions(clause
);
2058 void wxShape::ReadRegions(wxExpr
*clause
)
2062 // region1 = (regionName regionText x y width height minWidth minHeight proportionX proportionY
2063 // formatMode fontSize fontFamily fontStyle fontWeight textColour)
2065 char regionNameBuf
[20];
2066 char textNameBuf
[20];
2068 wxExpr
*regionExpr
= NULL
;
2069 wxExpr
*textExpr
= NULL
;
2070 sprintf(regionNameBuf
, "region%d", regionNo
);
2071 sprintf(textNameBuf
, "text%d", regionNo
);
2073 m_formatted
= TRUE
; // Assume text is formatted unless we prove otherwise
2075 while (regionExpr
= clause
->AttributeValue(regionNameBuf
))
2078 * Get the region information
2082 wxString
regionName("");
2083 wxString
regionText("");
2087 double height
= 0.0;
2088 double minWidth
= 5.0;
2089 double minHeight
= 5.0;
2090 double m_regionProportionX
= -1.0;
2091 double m_regionProportionY
= -1.0;
2092 int formatMode
= FORMAT_NONE
;
2094 int fontFamily
= wxSWISS
;
2095 int fontStyle
= wxNORMAL
;
2096 int fontWeight
= wxNORMAL
;
2097 wxString
regionTextColour("");
2098 wxString
penColour("");
2099 int penStyle
= wxSOLID
;
2101 if (regionExpr
->Type() == wxExprList
)
2103 wxExpr
*nameExpr
= regionExpr
->Nth(0);
2104 wxExpr
*textExpr
= regionExpr
->Nth(1);
2105 wxExpr
*xExpr
= regionExpr
->Nth(2);
2106 wxExpr
*yExpr
= regionExpr
->Nth(3);
2107 wxExpr
*widthExpr
= regionExpr
->Nth(4);
2108 wxExpr
*heightExpr
= regionExpr
->Nth(5);
2109 wxExpr
*minWidthExpr
= regionExpr
->Nth(6);
2110 wxExpr
*minHeightExpr
= regionExpr
->Nth(7);
2111 wxExpr
*propXExpr
= regionExpr
->Nth(8);
2112 wxExpr
*propYExpr
= regionExpr
->Nth(9);
2113 wxExpr
*formatExpr
= regionExpr
->Nth(10);
2114 wxExpr
*sizeExpr
= regionExpr
->Nth(11);
2115 wxExpr
*familyExpr
= regionExpr
->Nth(12);
2116 wxExpr
*styleExpr
= regionExpr
->Nth(13);
2117 wxExpr
*weightExpr
= regionExpr
->Nth(14);
2118 wxExpr
*colourExpr
= regionExpr
->Nth(15);
2119 wxExpr
*penColourExpr
= regionExpr
->Nth(16);
2120 wxExpr
*penStyleExpr
= regionExpr
->Nth(17);
2122 regionName
= nameExpr
->StringValue();
2123 regionText
= textExpr
->StringValue();
2125 x
= xExpr
->RealValue();
2126 y
= yExpr
->RealValue();
2128 width
= widthExpr
->RealValue();
2129 height
= heightExpr
->RealValue();
2131 minWidth
= minWidthExpr
->RealValue();
2132 minHeight
= minHeightExpr
->RealValue();
2134 m_regionProportionX
= propXExpr
->RealValue();
2135 m_regionProportionY
= propYExpr
->RealValue();
2137 formatMode
= (int) formatExpr
->IntegerValue();
2138 fontSize
= (int)sizeExpr
->IntegerValue();
2139 fontFamily
= (int)familyExpr
->IntegerValue();
2140 fontStyle
= (int)styleExpr
->IntegerValue();
2141 fontWeight
= (int)weightExpr
->IntegerValue();
2145 regionTextColour
= colourExpr
->StringValue();
2148 regionTextColour
= "BLACK";
2151 penColour
= penColourExpr
->StringValue();
2153 penStyle
= (int)penStyleExpr
->IntegerValue();
2155 wxFont
*font
= wxTheFontList
->FindOrCreateFont(fontSize
, fontFamily
, fontStyle
, fontWeight
);
2157 wxShapeRegion
*region
= new wxShapeRegion
;
2158 region
->SetProportions(m_regionProportionX
, m_regionProportionY
);
2159 region
->SetFont(font
);
2160 region
->SetSize(width
, height
);
2161 region
->SetPosition(x
, y
);
2162 region
->SetMinSize(minWidth
, minHeight
);
2163 region
->SetFormatMode(formatMode
);
2164 region
->SetPenStyle(penStyle
);
2165 if (penColour
!= "")
2166 region
->SetPenColour(penColour
);
2168 region
->m_textColour
= regionTextColour
;
2169 region
->m_regionText
= regionText
;
2170 region
->m_regionName
= regionName
;
2172 m_regions
.Append(region
);
2175 * Get the formatted text strings
2178 textExpr
= clause
->AttributeValue(textNameBuf
);
2179 if (textExpr
&& (textExpr
->Type() == wxExprList
))
2181 wxExpr
*node
= textExpr
->value
.first
;
2184 wxExpr
*string_expr
= node
;
2187 wxString
the_string("");
2189 // string_expr can either be a string, or a list of
2190 // 3 elements: x, y, and string.
2191 if (string_expr
->Type() == wxExprString
)
2193 the_string
= string_expr
->StringValue();
2194 m_formatted
= FALSE
;
2196 else if (string_expr
->Type() == wxExprList
)
2198 wxExpr
*first
= string_expr
->value
.first
;
2199 wxExpr
*second
= first
? first
->next
: NULL
;
2200 wxExpr
*third
= second
? second
->next
: NULL
;
2202 if (first
&& second
&& third
&&
2203 (first
->Type() == wxExprReal
|| first
->Type() == wxExprInteger
) &&
2204 (second
->Type() == wxExprReal
|| second
->Type() == wxExprInteger
) &&
2205 third
->Type() == wxExprString
)
2207 if (first
->Type() == wxExprReal
)
2208 the_x
= first
->RealValue();
2209 else the_x
= (double)first
->IntegerValue();
2211 if (second
->Type() == wxExprReal
)
2212 the_y
= second
->RealValue();
2213 else the_y
= (double)second
->IntegerValue();
2215 the_string
= third
->StringValue();
2220 wxShapeTextLine
*line
=
2221 new wxShapeTextLine(the_x
, the_y
, (char*) (const char*) the_string
);
2222 region
->m_formattedText
.Append(line
);
2229 sprintf(regionNameBuf
, "region%d", regionNo
);
2230 sprintf(textNameBuf
, "text%d", regionNo
);
2233 // Compatibility: check for no regions (old file).
2234 // Lines and divided rectangles must deal with this compatibility
2235 // theirselves. Composites _may_ not have any regions anyway.
2236 if ((m_regions
.Number() == 0) &&
2237 !this->IsKindOf(CLASSINFO(wxLineShape
)) && !this->IsKindOf(CLASSINFO(wxDividedShape
)) &&
2238 !this->IsKindOf(CLASSINFO(wxCompositeShape
)))
2240 wxShapeRegion
*newRegion
= new wxShapeRegion
;
2241 newRegion
->SetName("0");
2242 m_regions
.Append((wxObject
*)newRegion
);
2243 if (m_text
.Number() > 0)
2245 newRegion
->ClearText();
2246 wxNode
*node
= m_text
.First();
2249 wxShapeTextLine
*textLine
= (wxShapeTextLine
*)node
->Data();
2250 wxNode
*next
= node
->Next();
2251 newRegion
->GetFormattedText().Append((wxObject
*)textLine
);
2261 void wxShape::Copy(wxShape
& copy
)
2264 copy
.m_xpos
= m_xpos
;
2265 copy
.m_ypos
= m_ypos
;
2267 copy
.m_brush
= m_brush
;
2268 copy
.m_textColour
= m_textColour
;
2269 copy
.m_centreResize
= m_centreResize
;
2270 copy
.m_maintainAspectRatio
= m_maintainAspectRatio
;
2271 copy
.m_attachmentMode
= m_attachmentMode
;
2272 copy
.m_spaceAttachments
= m_spaceAttachments
;
2273 copy
.m_highlighted
= m_highlighted
;
2274 copy
.m_rotation
= m_rotation
;
2275 copy
.m_textColourName
= m_textColourName
;
2276 copy
.m_regionName
= m_regionName
;
2278 copy
.m_sensitivity
= m_sensitivity
;
2279 copy
.m_draggable
= m_draggable
;
2280 copy
.m_fixedWidth
= m_fixedWidth
;
2281 copy
.m_fixedHeight
= m_fixedHeight
;
2282 copy
.m_formatMode
= m_formatMode
;
2283 copy
.m_drawHandles
= m_drawHandles
;
2285 copy
.m_visible
= m_visible
;
2286 copy
.m_shadowMode
= m_shadowMode
;
2287 copy
.m_shadowOffsetX
= m_shadowOffsetX
;
2288 copy
.m_shadowOffsetY
= m_shadowOffsetY
;
2289 copy
.m_shadowBrush
= m_shadowBrush
;
2291 copy
.m_branchNeckLength
= m_branchNeckLength
;
2292 copy
.m_branchStemLength
= m_branchStemLength
;
2293 copy
.m_branchSpacing
= m_branchSpacing
;
2295 // Copy text regions
2296 copy
.ClearRegions();
2297 wxNode
*node
= m_regions
.First();
2300 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
2301 wxShapeRegion
*newRegion
= new wxShapeRegion(*region
);
2302 copy
.m_regions
.Append(newRegion
);
2303 node
= node
->Next();
2307 copy
.ClearAttachments();
2308 node
= m_attachmentPoints
.First();
2311 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
2312 wxAttachmentPoint
*newPoint
= new wxAttachmentPoint
;
2313 newPoint
->m_id
= point
->m_id
;
2314 newPoint
->m_x
= point
->m_x
;
2315 newPoint
->m_y
= point
->m_y
;
2316 copy
.m_attachmentPoints
.Append((wxObject
*)newPoint
);
2317 node
= node
->Next();
2321 copy
.m_lines
.Clear();
2322 node
= m_lines
.First();
2325 wxLineShape
* line
= (wxLineShape
*) node
->Data();
2326 copy
.m_lines
.Append(line
);
2327 node
= node
->Next();
2331 // Create and return a new, fully copied object.
2332 wxShape
*wxShape::CreateNewCopy(bool resetMapping
, bool recompute
)
2335 oglObjectCopyMapping
.Clear();
2337 wxShape
* newObject
= (wxShape
*) GetClassInfo()->CreateObject();
2339 wxASSERT( (newObject
!= NULL
) );
2340 wxASSERT( (newObject
->IsKindOf(CLASSINFO(wxShape
))) );
2344 if (GetEventHandler() != this)
2346 wxShapeEvtHandler
* newHandler
= GetEventHandler()->CreateNewCopy();
2347 newObject
->SetEventHandler(newHandler
);
2348 newObject
->SetPreviousHandler(NULL
);
2349 newHandler
->SetPreviousHandler(newObject
);
2350 newHandler
->SetShape(newObject
);
2354 newObject
->Recompute();
2358 // Does the copying for this object, including copying event
2359 // handler data if any. Calls the virtual Copy function.
2360 void wxShape::CopyWithHandler(wxShape
& copy
)
2364 if (GetEventHandler() != this)
2366 wxASSERT( copy
.GetEventHandler() != NULL
);
2367 wxASSERT( copy
.GetEventHandler() != (©
) );
2368 wxASSERT( GetEventHandler()->GetClassInfo() == copy
.GetEventHandler()->GetClassInfo() );
2369 GetEventHandler()->CopyData(* (copy
.GetEventHandler()));
2374 // Default - make 6 control points
2375 void wxShape::MakeControlPoints()
2377 double maxX
, maxY
, minX
, minY
;
2379 GetBoundingBoxMax(&maxX
, &maxY
);
2380 GetBoundingBoxMin(&minX
, &minY
);
2382 double widthMin
= (double)(minX
+ CONTROL_POINT_SIZE
+ 2);
2383 double heightMin
= (double)(minY
+ CONTROL_POINT_SIZE
+ 2);
2385 // Offsets from main object
2386 double top
= (double)(- (heightMin
/ 2.0));
2387 double bottom
= (double)(heightMin
/ 2.0 + (maxY
- minY
));
2388 double left
= (double)(- (widthMin
/ 2.0));
2389 double right
= (double)(widthMin
/ 2.0 + (maxX
- minX
));
2391 wxControlPoint
*control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, left
, top
,
2392 CONTROL_POINT_DIAGONAL
);
2393 m_canvas
->AddShape(control
);
2394 m_controlPoints
.Append(control
);
2396 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, 0, top
,
2397 CONTROL_POINT_VERTICAL
);
2398 m_canvas
->AddShape(control
);
2399 m_controlPoints
.Append(control
);
2401 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, right
, top
,
2402 CONTROL_POINT_DIAGONAL
);
2403 m_canvas
->AddShape(control
);
2404 m_controlPoints
.Append(control
);
2406 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, right
, 0,
2407 CONTROL_POINT_HORIZONTAL
);
2408 m_canvas
->AddShape(control
);
2409 m_controlPoints
.Append(control
);
2411 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, right
, bottom
,
2412 CONTROL_POINT_DIAGONAL
);
2413 m_canvas
->AddShape(control
);
2414 m_controlPoints
.Append(control
);
2416 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, 0, bottom
,
2417 CONTROL_POINT_VERTICAL
);
2418 m_canvas
->AddShape(control
);
2419 m_controlPoints
.Append(control
);
2421 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, left
, bottom
,
2422 CONTROL_POINT_DIAGONAL
);
2423 m_canvas
->AddShape(control
);
2424 m_controlPoints
.Append(control
);
2426 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, left
, 0,
2427 CONTROL_POINT_HORIZONTAL
);
2428 m_canvas
->AddShape(control
);
2429 m_controlPoints
.Append(control
);
2433 void wxShape::MakeMandatoryControlPoints()
2435 wxNode
*node
= m_children
.First();
2438 wxShape
*child
= (wxShape
*)node
->Data();
2439 child
->MakeMandatoryControlPoints();
2440 node
= node
->Next();
2444 void wxShape::ResetMandatoryControlPoints()
2446 wxNode
*node
= m_children
.First();
2449 wxShape
*child
= (wxShape
*)node
->Data();
2450 child
->ResetMandatoryControlPoints();
2451 node
= node
->Next();
2455 void wxShape::ResetControlPoints()
2457 ResetMandatoryControlPoints();
2459 if (m_controlPoints
.Number() < 1)
2462 double maxX
, maxY
, minX
, minY
;
2464 GetBoundingBoxMax(&maxX
, &maxY
);
2465 GetBoundingBoxMin(&minX
, &minY
);
2467 double widthMin
= (double)(minX
+ CONTROL_POINT_SIZE
+ 2);
2468 double heightMin
= (double)(minY
+ CONTROL_POINT_SIZE
+ 2);
2470 // Offsets from main object
2471 double top
= (double)(- (heightMin
/ 2.0));
2472 double bottom
= (double)(heightMin
/ 2.0 + (maxY
- minY
));
2473 double left
= (double)(- (widthMin
/ 2.0));
2474 double right
= (double)(widthMin
/ 2.0 + (maxX
- minX
));
2476 wxNode
*node
= m_controlPoints
.First();
2477 wxControlPoint
*control
= (wxControlPoint
*)node
->Data();
2478 control
->m_xoffset
= left
; control
->m_yoffset
= top
;
2480 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2481 control
->m_xoffset
= 0; control
->m_yoffset
= top
;
2483 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2484 control
->m_xoffset
= right
; control
->m_yoffset
= top
;
2486 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2487 control
->m_xoffset
= right
; control
->m_yoffset
= 0;
2489 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2490 control
->m_xoffset
= right
; control
->m_yoffset
= bottom
;
2492 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2493 control
->m_xoffset
= 0; control
->m_yoffset
= bottom
;
2495 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2496 control
->m_xoffset
= left
; control
->m_yoffset
= bottom
;
2498 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2499 control
->m_xoffset
= left
; control
->m_yoffset
= 0;
2502 void wxShape::DeleteControlPoints(wxDC
*dc
)
2504 wxNode
*node
= m_controlPoints
.First();
2507 wxControlPoint
*control
= (wxControlPoint
*)node
->Data();
2509 control
->GetEventHandler()->OnErase(*dc
);
2510 m_canvas
->RemoveShape(control
);
2513 node
= m_controlPoints
.First();
2515 // Children of divisions are contained objects,
2517 if (!IsKindOf(CLASSINFO(wxDivisionShape
)))
2519 node
= m_children
.First();
2522 wxShape
*child
= (wxShape
*)node
->Data();
2523 child
->DeleteControlPoints(dc
);
2524 node
= node
->Next();
2529 void wxShape::OnDrawControlPoints(wxDC
& dc
)
2534 dc
.SetBrush(wxBLACK_BRUSH
);
2535 dc
.SetPen(wxBLACK_PEN
);
2537 wxNode
*node
= m_controlPoints
.First();
2540 wxControlPoint
*control
= (wxControlPoint
*)node
->Data();
2542 node
= node
->Next();
2544 // Children of divisions are contained objects,
2546 // This test bypasses the type facility for speed
2547 // (critical when drawing)
2548 if (!IsKindOf(CLASSINFO(wxDivisionShape
)))
2550 node
= m_children
.First();
2553 wxShape
*child
= (wxShape
*)node
->Data();
2554 child
->GetEventHandler()->OnDrawControlPoints(dc
);
2555 node
= node
->Next();
2560 void wxShape::OnEraseControlPoints(wxDC
& dc
)
2562 wxNode
*node
= m_controlPoints
.First();
2565 wxControlPoint
*control
= (wxControlPoint
*)node
->Data();
2567 node
= node
->Next();
2569 if (!IsKindOf(CLASSINFO(wxDivisionShape
)))
2571 node
= m_children
.First();
2574 wxShape
*child
= (wxShape
*)node
->Data();
2575 child
->GetEventHandler()->OnEraseControlPoints(dc
);
2576 node
= node
->Next();
2581 void wxShape::Select(bool select
, wxDC
* dc
)
2583 m_selected
= select
;
2586 MakeControlPoints();
2587 // Children of divisions are contained objects,
2589 if (!IsKindOf(CLASSINFO(wxDivisionShape
)))
2591 wxNode
*node
= m_children
.First();
2594 wxShape
*child
= (wxShape
*)node
->Data();
2595 child
->MakeMandatoryControlPoints();
2596 node
= node
->Next();
2600 GetEventHandler()->OnDrawControlPoints(*dc
);
2604 DeleteControlPoints(dc
);
2605 if (!IsKindOf(CLASSINFO(wxDivisionShape
)))
2607 wxNode
*node
= m_children
.First();
2610 wxShape
*child
= (wxShape
*)node
->Data();
2611 child
->DeleteControlPoints(dc
);
2612 node
= node
->Next();
2618 bool wxShape::Selected() const
2623 bool wxShape::AncestorSelected() const
2625 if (m_selected
) return TRUE
;
2629 return GetParent()->AncestorSelected();
2632 int wxShape::GetNumberOfAttachments() const
2634 // Should return the MAXIMUM attachment point id here,
2635 // so higher-level functions can iterate through all attachments,
2636 // even if they're not contiguous.
2637 if (m_attachmentPoints
.Number() == 0)
2642 wxNode
*node
= m_attachmentPoints
.First();
2645 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
2646 if (point
->m_id
> maxN
)
2648 node
= node
->Next();
2654 bool wxShape::AttachmentIsValid(int attachment
) const
2656 if (m_attachmentPoints
.Number() == 0)
2658 return ((attachment
>= 0) && (attachment
< 4)) ;
2661 wxNode
*node
= m_attachmentPoints
.First();
2664 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
2665 if (point
->m_id
== attachment
)
2667 node
= node
->Next();
2672 bool wxShape::GetAttachmentPosition(int attachment
, double *x
, double *y
,
2673 int nth
, int no_arcs
, wxLineShape
*line
)
2675 if (m_attachmentMode
== ATTACHMENT_MODE_NONE
)
2677 *x
= m_xpos
; *y
= m_ypos
;
2680 else if (m_attachmentMode
== ATTACHMENT_MODE_BRANCHING
)
2682 wxRealPoint pt
, stemPt
;
2683 GetBranchingAttachmentPoint(attachment
, nth
, pt
, stemPt
);
2688 else if (m_attachmentMode
== ATTACHMENT_MODE_EDGE
)
2690 if (m_attachmentPoints
.Number() > 0)
2692 wxNode
*node
= m_attachmentPoints
.First();
2695 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
2696 if (point
->m_id
== attachment
)
2698 *x
= (double)(m_xpos
+ point
->m_x
);
2699 *y
= (double)(m_ypos
+ point
->m_y
);
2702 node
= node
->Next();
2704 *x
= m_xpos
; *y
= m_ypos
;
2709 // Assume is rectangular
2711 GetBoundingBoxMax(&w
, &h
);
2712 double top
= (double)(m_ypos
+ h
/2.0);
2713 double bottom
= (double)(m_ypos
- h
/2.0);
2714 double left
= (double)(m_xpos
- w
/2.0);
2715 double right
= (double)(m_xpos
+ w
/2.0);
2717 bool isEnd
= (line
&& line
->IsEnd(this));
2719 int physicalAttachment
= LogicalToPhysicalAttachment(attachment
);
2722 switch (physicalAttachment
)
2726 wxRealPoint pt
= CalcSimpleAttachment(wxRealPoint(left
, bottom
), wxRealPoint(right
, bottom
),
2727 nth
, no_arcs
, line
);
2729 *x
= pt
.x
; *y
= pt
.y
;
2734 wxRealPoint pt
= CalcSimpleAttachment(wxRealPoint(right
, bottom
), wxRealPoint(right
, top
),
2735 nth
, no_arcs
, line
);
2737 *x
= pt
.x
; *y
= pt
.y
;
2742 wxRealPoint pt
= CalcSimpleAttachment(wxRealPoint(left
, top
), wxRealPoint(right
, top
),
2743 nth
, no_arcs
, line
);
2745 *x
= pt
.x
; *y
= pt
.y
;
2750 wxRealPoint pt
= CalcSimpleAttachment(wxRealPoint(left
, bottom
), wxRealPoint(left
, top
),
2751 nth
, no_arcs
, line
);
2753 *x
= pt
.x
; *y
= pt
.y
;
2768 void wxShape::GetBoundingBoxMax(double *w
, double *h
)
2771 GetBoundingBoxMin(&ww
, &hh
);
2772 if (m_shadowMode
!= SHADOW_NONE
)
2774 ww
+= m_shadowOffsetX
;
2775 hh
+= m_shadowOffsetY
;
2781 // Returns TRUE if image is a descendant of this composite
2782 bool wxShape::HasDescendant(wxShape
*image
)
2786 wxNode
*node
= m_children
.First();
2789 wxShape
*child
= (wxShape
*)node
->Data();
2790 bool ans
= child
->HasDescendant(image
);
2793 node
= node
->Next();
2798 // Clears points from a list of wxRealPoints, and clears list
2799 void wxShape::ClearPointList(wxList
& list
)
2801 wxNode
* node
= list
.First();
2804 wxRealPoint
* pt
= (wxRealPoint
*) node
->Data();
2807 node
= node
->Next();
2812 // Assuming the attachment lies along a vertical or horizontal line,
2813 // calculate the position on that point.
2814 wxRealPoint
wxShape::CalcSimpleAttachment(const wxRealPoint
& pt1
, const wxRealPoint
& pt2
,
2815 int nth
, int noArcs
, wxLineShape
* line
)
2817 bool isEnd
= (line
&& line
->IsEnd(this));
2819 // Are we horizontal or vertical?
2820 bool isHorizontal
= (oglRoughlyEqual(pt1
.y
, pt2
.y
) == TRUE
);
2826 wxRealPoint firstPoint
, secondPoint
;
2838 if (m_spaceAttachments
)
2840 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
2842 // Align line according to the next handle along
2843 wxRealPoint
*point
= line
->GetNextControlPoint(this);
2844 if (point
->x
< firstPoint
.x
)
2846 else if (point
->x
> secondPoint
.x
)
2852 x
= firstPoint
.x
+ (nth
+ 1)*(secondPoint
.x
- firstPoint
.x
)/(noArcs
+ 1);
2854 else x
= (secondPoint
.x
- firstPoint
.x
)/2.0; // Midpoint
2860 wxASSERT( oglRoughlyEqual(pt1
.x
, pt2
.x
) == TRUE
);
2862 wxRealPoint firstPoint
, secondPoint
;
2874 if (m_spaceAttachments
)
2876 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
2878 // Align line according to the next handle along
2879 wxRealPoint
*point
= line
->GetNextControlPoint(this);
2880 if (point
->y
< firstPoint
.y
)
2882 else if (point
->y
> secondPoint
.y
)
2888 y
= firstPoint
.y
+ (nth
+ 1)*(secondPoint
.y
- firstPoint
.y
)/(noArcs
+ 1);
2890 else y
= (secondPoint
.y
- firstPoint
.y
)/2.0; // Midpoint
2895 return wxRealPoint(x
, y
);
2898 // Return the zero-based position in m_lines of line.
2899 int wxShape::GetLinePosition(wxLineShape
* line
)
2902 for (i
= 0; i
< m_lines
.Number(); i
++)
2903 if ((wxLineShape
*) (m_lines
.Nth(i
)->Data()) == line
)
2913 // shoulder1 ->---------<- shoulder2
2915 // <- branching attachment point N-1
2917 // This function gets information about where branching connections go.
2918 // Returns FALSE if there are no lines at this attachment.
2919 bool wxShape::GetBranchingAttachmentInfo(int attachment
, wxRealPoint
& root
, wxRealPoint
& neck
,
2920 wxRealPoint
& shoulder1
, wxRealPoint
& shoulder2
)
2922 int physicalAttachment
= LogicalToPhysicalAttachment(attachment
);
2924 // Number of lines at this attachment.
2925 int lineCount
= GetAttachmentLineCount(attachment
);
2930 int totalBranchLength
= m_branchSpacing
* (lineCount
- 1);
2932 root
= GetBranchingAttachmentRoot(attachment
);
2934 // Assume that we have attachment points 0 to 3: top, right, bottom, left.
2935 switch (physicalAttachment
)
2940 neck
.y
= root
.y
- m_branchNeckLength
;
2942 shoulder1
.x
= root
.x
- (totalBranchLength
/2.0) ;
2943 shoulder2
.x
= root
.x
+ (totalBranchLength
/2.0) ;
2945 shoulder1
.y
= neck
.y
;
2946 shoulder2
.y
= neck
.y
;
2951 neck
.x
= root
.x
+ m_branchNeckLength
;
2954 shoulder1
.x
= neck
.x
;
2955 shoulder2
.x
= neck
.x
;
2957 shoulder1
.y
= neck
.y
- (totalBranchLength
/2.0) ;
2958 shoulder2
.y
= neck
.y
+ (totalBranchLength
/2.0) ;
2964 neck
.y
= root
.y
+ m_branchNeckLength
;
2966 shoulder1
.x
= root
.x
- (totalBranchLength
/2.0) ;
2967 shoulder2
.x
= root
.x
+ (totalBranchLength
/2.0) ;
2969 shoulder1
.y
= neck
.y
;
2970 shoulder2
.y
= neck
.y
;
2975 neck
.x
= root
.x
- m_branchNeckLength
;
2978 shoulder1
.x
= neck
.x
;
2979 shoulder2
.x
= neck
.x
;
2981 shoulder1
.y
= neck
.y
- (totalBranchLength
/2.0) ;
2982 shoulder2
.y
= neck
.y
+ (totalBranchLength
/2.0) ;
2987 wxFAIL_MSG( "Unrecognised attachment point in GetBranchingAttachmentInfo." );
2994 // n is the number of the adjoining line, from 0 to N-1 where N is the number of lines
2995 // at this attachment point.
2996 // Get the attachment point where the arc joins the stem, and also the point where the
2997 // the stem meets the shoulder.
2998 bool wxShape::GetBranchingAttachmentPoint(int attachment
, int n
, wxRealPoint
& pt
, wxRealPoint
& stemPt
)
3000 int physicalAttachment
= LogicalToPhysicalAttachment(attachment
);
3002 wxRealPoint root
, neck
, shoulder1
, shoulder2
;
3003 GetBranchingAttachmentInfo(attachment
, root
, neck
, shoulder1
, shoulder2
);
3005 // Assume that we have attachment points 0 to 3: top, right, bottom, left.
3006 switch (physicalAttachment
)
3010 pt
.y
= neck
.y
- m_branchStemLength
;
3011 pt
.x
= shoulder1
.x
+ n
*m_branchSpacing
;
3019 pt
.y
= neck
.y
+ m_branchStemLength
;
3020 pt
.x
= shoulder1
.x
+ n
*m_branchSpacing
;
3028 pt
.x
= neck
.x
+ m_branchStemLength
;
3029 pt
.y
= shoulder1
.y
+ n
*m_branchSpacing
;
3037 pt
.x
= neck
.x
- m_branchStemLength
;
3038 pt
.y
= shoulder1
.y
+ n
*m_branchSpacing
;
3046 wxFAIL_MSG( "Unrecognised attachment point in GetBranchingAttachmentPoint." );
3054 // Get the number of lines at this attachment position.
3055 int wxShape::GetAttachmentLineCount(int attachment
) const
3058 wxNode
* node
= m_lines
.First();
3061 wxLineShape
* lineShape
= (wxLineShape
*) node
->Data();
3062 if ((lineShape
->GetFrom() == this) && (lineShape
->GetAttachmentFrom() == attachment
))
3064 else if ((lineShape
->GetTo() == this) && (lineShape
->GetAttachmentTo() == attachment
))
3067 node
= node
->Next();
3072 // This function gets the root point at the given attachment.
3073 wxRealPoint
wxShape::GetBranchingAttachmentRoot(int attachment
)
3075 int physicalAttachment
= LogicalToPhysicalAttachment(attachment
);
3079 double width
, height
;
3080 GetBoundingBoxMax(& width
, & height
);
3082 // Assume that we have attachment points 0 to 3: top, right, bottom, left.
3083 switch (physicalAttachment
)
3088 root
.y
= GetY() - height
/2.0;
3093 root
.x
= GetX() + width
/2.0;
3100 root
.y
= GetY() + height
/2.0;
3105 root
.x
= GetX() - width
/2.0;
3111 wxFAIL_MSG( "Unrecognised attachment point in GetBranchingAttachmentRoot." );
3118 // Draw or erase the branches (not the actual arcs though)
3119 void wxShape::OnDrawBranches(wxDC
& dc
, int attachment
, bool erase
)
3121 int count
= GetAttachmentLineCount(attachment
);
3125 wxRealPoint root
, neck
, shoulder1
, shoulder2
;
3126 GetBranchingAttachmentInfo(attachment
, root
, neck
, shoulder1
, shoulder2
);
3130 dc
.SetPen(*wxWHITE_PEN
);
3131 dc
.SetBrush(*wxWHITE_BRUSH
);
3135 dc
.SetPen(*wxBLACK_PEN
);
3136 dc
.SetBrush(*wxBLACK_BRUSH
);
3140 dc
.DrawLine((long) root
.x
, (long) root
.y
, (long) neck
.x
, (long) neck
.y
);
3144 // Draw shoulder-to-shoulder line
3145 dc
.DrawLine((long) shoulder1
.x
, (long) shoulder1
.y
, (long) shoulder2
.x
, (long) shoulder2
.y
);
3147 // Draw all the little branches
3149 for (i
= 0; i
< count
; i
++)
3151 wxRealPoint pt
, stemPt
;
3152 GetBranchingAttachmentPoint(attachment
, i
, pt
, stemPt
);
3153 dc
.DrawLine((long) stemPt
.x
, (long) stemPt
.y
, (long) pt
.x
, (long) pt
.y
);
3155 if (GetBranchStyle() & BRANCHING_ATTACHMENT_BLOB
)
3158 // dc.DrawEllipse((long) (stemPt.x + 0.5 - (blobSize/2.0)), (long) (stemPt.y + 0.5 - (blobSize/2.0)), blobSize, blobSize);
3159 dc
.DrawEllipse((long) (stemPt
.x
- (blobSize
/2.0)), (long) (stemPt
.y
- (blobSize
/2.0)), blobSize
, blobSize
);
3164 // Draw or erase the branches (not the actual arcs though)
3165 void wxShape::OnDrawBranches(wxDC
& dc
, bool erase
)
3167 if (m_attachmentMode
!= ATTACHMENT_MODE_BRANCHING
)
3170 int count
= GetNumberOfAttachments();
3172 for (i
= 0; i
< count
; i
++)
3173 OnDrawBranches(dc
, i
, erase
);
3176 // Only get the attachment position at the _edge_ of the shape, ignoring
3177 // branching mode. This is used e.g. to indicate the edge of interest, not the point
3178 // on the attachment branch.
3179 bool wxShape::GetAttachmentPositionEdge(int attachment
, double *x
, double *y
,
3180 int nth
, int no_arcs
, wxLineShape
*line
)
3182 int oldMode
= m_attachmentMode
;
3184 // Calculate as if to edge, not branch
3185 if (m_attachmentMode
== ATTACHMENT_MODE_BRANCHING
)
3186 m_attachmentMode
= ATTACHMENT_MODE_EDGE
;
3187 bool success
= GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
3188 m_attachmentMode
= oldMode
;
3193 // Rotate the standard attachment point from physical (0 is always North)
3194 // to logical (0 -> 1 if rotated by 90 degrees)
3195 int wxShape::PhysicalToLogicalAttachment(int physicalAttachment
) const
3197 const double pi
= 3.1415926535897932384626433832795 ;
3199 if (oglRoughlyEqual(GetRotation(), 0.0))
3201 i
= physicalAttachment
;
3203 else if (oglRoughlyEqual(GetRotation(), (pi
/2.0)))
3205 i
= physicalAttachment
- 1;
3207 else if (oglRoughlyEqual(GetRotation(), pi
))
3209 i
= physicalAttachment
- 2;
3211 else if (oglRoughlyEqual(GetRotation(), (3.0*pi
/2.0)))
3213 i
= physicalAttachment
- 3;
3216 // Can't handle -- assume the same.
3217 return physicalAttachment
;
3225 // Rotate the standard attachment point from logical
3226 // to physical (0 is always North)
3227 int wxShape::LogicalToPhysicalAttachment(int logicalAttachment
) const
3229 const double pi
= 3.1415926535897932384626433832795 ;
3231 if (oglRoughlyEqual(GetRotation(), 0.0))
3233 i
= logicalAttachment
;
3235 else if (oglRoughlyEqual(GetRotation(), (pi
/2.0)))
3237 i
= logicalAttachment
+ 1;
3239 else if (oglRoughlyEqual(GetRotation(), pi
))
3241 i
= logicalAttachment
+ 2;
3243 else if (oglRoughlyEqual(GetRotation(), (3.0*pi
/2.0)))
3245 i
= logicalAttachment
+ 3;
3248 // Can't handle -- assume the same.
3249 return logicalAttachment
;
3257 void wxShape::Rotate(double WXUNUSED(x
), double WXUNUSED(y
), double theta
)
3259 const double pi
= 3.1415926535897932384626433832795 ;
3261 if (m_rotation
< 0.0)
3265 else if (m_rotation
> 2*pi
)