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>
27 #include <wx/wxexpr.h>
43 #include <wx/ogl/basic.h>
44 #include <wx/ogl/basicp.h>
45 #include <wx/ogl/composit.h>
46 #include <wx/ogl/lines.h>
47 #include <wx/ogl/canvas.h>
48 #include <wx/ogl/divided.h>
49 #include <wx/ogl/misc.h>
51 // Control point types
52 // Rectangle and most other shapes
53 #define CONTROL_POINT_VERTICAL 1
54 #define CONTROL_POINT_HORIZONTAL 2
55 #define CONTROL_POINT_DIAGONAL 3
58 #define CONTROL_POINT_ENDPOINT_TO 4
59 #define CONTROL_POINT_ENDPOINT_FROM 5
60 #define CONTROL_POINT_LINE 6
62 IMPLEMENT_DYNAMIC_CLASS(wxShapeTextLine
, wxObject
)
63 IMPLEMENT_DYNAMIC_CLASS(wxAttachmentPoint
, wxObject
)
65 wxShapeTextLine::wxShapeTextLine(double the_x
, double the_y
, const wxString
& the_line
)
67 m_x
= the_x
; m_y
= the_y
; m_line
= the_line
;
70 wxShapeTextLine::~wxShapeTextLine()
74 IMPLEMENT_ABSTRACT_CLASS(wxShapeEvtHandler
, wxObject
)
76 wxShapeEvtHandler::wxShapeEvtHandler(wxShapeEvtHandler
*prev
, wxShape
*shape
)
78 m_previousHandler
= prev
;
79 m_handlerShape
= shape
;
82 wxShapeEvtHandler::~wxShapeEvtHandler()
86 // Creates a copy of this event handler.
87 wxShapeEvtHandler
* wxShapeEvtHandler::CreateNewCopy()
89 wxShapeEvtHandler
* newObject
= (wxShapeEvtHandler
*) GetClassInfo()->CreateObject();
91 wxASSERT( (newObject
!= NULL
) );
92 wxASSERT( (newObject
->IsKindOf(CLASSINFO(wxShapeEvtHandler
))) );
94 newObject
->m_previousHandler
= newObject
;
102 void wxShapeEvtHandler::OnDelete()
104 if (this != GetShape())
108 void wxShapeEvtHandler::OnDraw(wxDC
& dc
)
110 if (m_previousHandler
)
111 m_previousHandler
->OnDraw(dc
);
114 void wxShapeEvtHandler::OnMoveLinks(wxDC
& dc
)
116 if (m_previousHandler
)
117 m_previousHandler
->OnMoveLinks(dc
);
120 void wxShapeEvtHandler::OnMoveLink(wxDC
& dc
, bool moveControlPoints
)
122 if (m_previousHandler
)
123 m_previousHandler
->OnMoveLink(dc
, moveControlPoints
);
126 void wxShapeEvtHandler::OnDrawContents(wxDC
& dc
)
128 if (m_previousHandler
)
129 m_previousHandler
->OnDrawContents(dc
);
132 void wxShapeEvtHandler::OnDrawBranches(wxDC
& dc
, bool erase
)
134 if (m_previousHandler
)
135 m_previousHandler
->OnDrawBranches(dc
, erase
);
138 void wxShapeEvtHandler::OnSize(double x
, double y
)
140 if (m_previousHandler
)
141 m_previousHandler
->OnSize(x
, y
);
144 bool wxShapeEvtHandler::OnMovePre(wxDC
& dc
, double x
, double y
, double old_x
, double old_y
, bool display
)
146 if (m_previousHandler
)
147 return m_previousHandler
->OnMovePre(dc
, x
, y
, old_x
, old_y
, display
);
152 void wxShapeEvtHandler::OnMovePost(wxDC
& dc
, double x
, double y
, double old_x
, double old_y
, bool display
)
154 if (m_previousHandler
)
155 m_previousHandler
->OnMovePost(dc
, x
, y
, old_x
, old_y
, display
);
158 void wxShapeEvtHandler::OnErase(wxDC
& dc
)
160 if (m_previousHandler
)
161 m_previousHandler
->OnErase(dc
);
164 void wxShapeEvtHandler::OnEraseContents(wxDC
& dc
)
166 if (m_previousHandler
)
167 m_previousHandler
->OnEraseContents(dc
);
170 void wxShapeEvtHandler::OnHighlight(wxDC
& dc
)
172 if (m_previousHandler
)
173 m_previousHandler
->OnHighlight(dc
);
176 void wxShapeEvtHandler::OnLeftClick(double x
, double y
, int keys
, int attachment
)
178 if (m_previousHandler
)
179 m_previousHandler
->OnLeftClick(x
, y
, keys
, attachment
);
182 void wxShapeEvtHandler::OnLeftDoubleClick(double x
, double y
, int keys
, int attachment
)
184 if (m_previousHandler
)
185 m_previousHandler
->OnLeftDoubleClick(x
, y
, keys
, attachment
);
188 void wxShapeEvtHandler::OnRightClick(double x
, double y
, int keys
, int attachment
)
190 if (m_previousHandler
)
191 m_previousHandler
->OnRightClick(x
, y
, keys
, attachment
);
194 void wxShapeEvtHandler::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
196 if (m_previousHandler
)
197 m_previousHandler
->OnDragLeft(draw
, x
, y
, keys
, attachment
);
200 void wxShapeEvtHandler::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
202 if (m_previousHandler
)
203 m_previousHandler
->OnBeginDragLeft(x
, y
, keys
, attachment
);
206 void wxShapeEvtHandler::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
208 if (m_previousHandler
)
209 m_previousHandler
->OnEndDragLeft(x
, y
, keys
, attachment
);
212 void wxShapeEvtHandler::OnDragRight(bool draw
, double x
, double y
, int keys
, int attachment
)
214 if (m_previousHandler
)
215 m_previousHandler
->OnDragRight(draw
, x
, y
, keys
, attachment
);
218 void wxShapeEvtHandler::OnBeginDragRight(double x
, double y
, int keys
, int attachment
)
220 if (m_previousHandler
)
221 m_previousHandler
->OnBeginDragRight(x
, y
, keys
, attachment
);
224 void wxShapeEvtHandler::OnEndDragRight(double x
, double y
, int keys
, int attachment
)
226 if (m_previousHandler
)
227 m_previousHandler
->OnEndDragRight(x
, y
, keys
, attachment
);
230 // Control points ('handles') redirect control to the actual shape, to make it easier
231 // to override sizing behaviour.
232 void wxShapeEvtHandler::OnSizingDragLeft(wxControlPoint
* pt
, bool draw
, double x
, double y
, int keys
, int attachment
)
234 if (m_previousHandler
)
235 m_previousHandler
->OnSizingDragLeft(pt
, draw
, x
, y
, keys
, attachment
);
238 void wxShapeEvtHandler::OnSizingBeginDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int attachment
)
240 if (m_previousHandler
)
241 m_previousHandler
->OnSizingBeginDragLeft(pt
, x
, y
, keys
, attachment
);
244 void wxShapeEvtHandler::OnSizingEndDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int attachment
)
246 if (m_previousHandler
)
247 m_previousHandler
->OnSizingEndDragLeft(pt
, x
, y
, keys
, attachment
);
250 void wxShapeEvtHandler::OnDrawOutline(wxDC
& dc
, double x
, double y
, double w
, double h
)
252 if (m_previousHandler
)
253 m_previousHandler
->OnDrawOutline(dc
, x
, y
, w
, h
);
256 void wxShapeEvtHandler::OnDrawControlPoints(wxDC
& dc
)
258 if (m_previousHandler
)
259 m_previousHandler
->OnDrawControlPoints(dc
);
262 void wxShapeEvtHandler::OnEraseControlPoints(wxDC
& dc
)
264 if (m_previousHandler
)
265 m_previousHandler
->OnEraseControlPoints(dc
);
268 // Can override this to prevent or intercept line reordering.
269 void wxShapeEvtHandler::OnChangeAttachment(int attachment
, wxLineShape
* line
, wxList
& ordering
)
271 if (m_previousHandler
)
272 m_previousHandler
->OnChangeAttachment(attachment
, line
, ordering
);
275 IMPLEMENT_ABSTRACT_CLASS(wxShape
, wxShapeEvtHandler
)
277 wxShape::wxShape(wxShapeCanvas
*can
)
279 m_eventHandler
= this;
284 m_xpos
= 0.0; m_ypos
= 0.0;
285 m_pen
= g_oglBlackPen
;
286 m_brush
= wxWHITE_BRUSH
;
287 m_font
= g_oglNormalFont
;
288 m_textColour
= wxBLACK
;
289 m_textColourName
= "BLACK";
293 m_attachmentMode
= ATTACHMENT_MODE_NONE
;
294 m_spaceAttachments
= TRUE
;
295 m_disableLabel
= FALSE
;
296 m_fixedWidth
= FALSE
;
297 m_fixedHeight
= FALSE
;
298 m_drawHandles
= TRUE
;
299 m_sensitivity
= OP_ALL
;
302 m_formatMode
= FORMAT_CENTRE_HORIZ
| FORMAT_CENTRE_VERT
;
303 m_shadowMode
= SHADOW_NONE
;
306 m_shadowBrush
= wxBLACK_BRUSH
;
310 m_centreResize
= TRUE
;
311 m_maintainAspectRatio
= FALSE
;
312 m_highlighted
= FALSE
;
314 m_branchNeckLength
= 10;
315 m_branchStemLength
= 10;
316 m_branchSpacing
= 10;
317 m_branchStyle
= BRANCHING_ATTACHMENT_NORMAL
;
319 // Set up a default region. Much of the above will be put into
320 // the region eventually (the duplication is for compatibility)
321 wxShapeRegion
*region
= new wxShapeRegion
;
322 m_regions
.Append(region
);
323 region
->SetName("0");
324 region
->SetFont(g_oglNormalFont
);
325 region
->SetFormatMode(FORMAT_CENTRE_HORIZ
| FORMAT_CENTRE_VERT
);
326 region
->SetColour("BLACK");
332 m_parent
->GetChildren().DeleteObject(this);
339 m_canvas
->RemoveShape(this);
346 GetEventHandler()->OnDelete();
349 void wxShape::SetHighlight(bool hi
, bool recurse
)
354 wxNode
*node
= m_children
.First();
357 wxShape
*child
= (wxShape
*)node
->Data();
358 child
->SetHighlight(hi
, recurse
);
364 void wxShape::SetSensitivityFilter(int sens
, bool recursive
)
366 if (sens
& OP_DRAG_LEFT
)
371 m_sensitivity
= sens
;
374 wxNode
*node
= m_children
.First();
377 wxShape
*obj
= (wxShape
*)node
->Data();
378 obj
->SetSensitivityFilter(sens
, TRUE
);
384 void wxShape::SetDraggable(bool drag
, bool recursive
)
388 m_sensitivity
|= OP_DRAG_LEFT
;
390 if (m_sensitivity
& OP_DRAG_LEFT
)
391 m_sensitivity
= m_sensitivity
- OP_DRAG_LEFT
;
395 wxNode
*node
= m_children
.First();
398 wxShape
*obj
= (wxShape
*)node
->Data();
399 obj
->SetDraggable(drag
, TRUE
);
405 void wxShape::SetDrawHandles(bool drawH
)
407 m_drawHandles
= drawH
;
408 wxNode
*node
= m_children
.First();
411 wxShape
*obj
= (wxShape
*)node
->Data();
412 obj
->SetDrawHandles(drawH
);
417 void wxShape::SetShadowMode(int mode
, bool redraw
)
419 if (redraw
&& GetCanvas())
421 wxClientDC
dc(GetCanvas());
422 GetCanvas()->PrepareDC(dc
);
435 void wxShape::SetCanvas(wxShapeCanvas
*theCanvas
)
437 m_canvas
= theCanvas
;
438 wxNode
*node
= m_children
.First();
441 wxShape
*child
= (wxShape
*)node
->Data();
442 child
->SetCanvas(theCanvas
);
447 void wxShape::AddToCanvas(wxShapeCanvas
*theCanvas
, wxShape
*addAfter
)
449 theCanvas
->AddShape(this, addAfter
);
450 wxNode
*node
= m_children
.First();
451 wxShape
*lastImage
= this;
454 wxShape
*object
= (wxShape
*)node
->Data();
455 object
->AddToCanvas(theCanvas
, lastImage
);
462 // Insert at front of canvas
463 void wxShape::InsertInCanvas(wxShapeCanvas
*theCanvas
)
465 theCanvas
->InsertShape(this);
466 wxNode
*node
= m_children
.First();
467 wxShape
*lastImage
= this;
470 wxShape
*object
= (wxShape
*)node
->Data();
471 object
->AddToCanvas(theCanvas
, lastImage
);
478 void wxShape::RemoveFromCanvas(wxShapeCanvas
*theCanvas
)
482 theCanvas
->RemoveShape(this);
483 wxNode
*node
= m_children
.First();
486 wxShape
*object
= (wxShape
*)node
->Data();
487 object
->RemoveFromCanvas(theCanvas
);
493 void wxShape::ClearAttachments()
495 wxNode
*node
= m_attachmentPoints
.First();
498 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
502 m_attachmentPoints
.Clear();
505 void wxShape::ClearText(int regionId
)
509 m_text
.DeleteContents(TRUE
);
511 m_text
.DeleteContents(FALSE
);
513 wxNode
*node
= m_regions
.Nth(regionId
);
516 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
520 void wxShape::ClearRegions()
522 wxNode
*node
= m_regions
.First();
525 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
526 wxNode
*next
= node
->Next();
533 void wxShape::AddRegion(wxShapeRegion
*region
)
535 m_regions
.Append(region
);
538 void wxShape::SetDefaultRegionSize()
540 wxNode
*node
= m_regions
.First();
542 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
544 GetBoundingBoxMin(&w
, &h
);
545 region
->SetSize(w
, h
);
548 bool wxShape::HitTest(double x
, double y
, int *attachment
, double *distance
)
553 double width
= 0.0, height
= 0.0;
554 GetBoundingBoxMin(&width
, &height
);
555 if (fabs(width
) < 4.0) width
= 4.0;
556 if (fabs(height
) < 4.0) height
= 4.0;
558 width
+= (double)4.0; height
+= (double)4.0; // Allowance for inaccurate mousing
560 double left
= (double)(m_xpos
- (width
/2.0));
561 double top
= (double)(m_ypos
- (height
/2.0));
562 double right
= (double)(m_xpos
+ (width
/2.0));
563 double bottom
= (double)(m_ypos
+ (height
/2.0));
565 int nearest_attachment
= 0;
567 // If within the bounding box, check the attachment points
568 // within the object.
570 if (x
>= left
&& x
<= right
&& y
>= top
&& y
<= bottom
)
572 int n
= GetNumberOfAttachments();
573 double nearest
= 999999.0;
575 // GetAttachmentPosition[Edge] takes a logical attachment position,
576 // i.e. if it's rotated through 90%, position 0 is East-facing.
578 for (int i
= 0; i
< n
; i
++)
581 if (GetAttachmentPositionEdge(i
, &xp
, &yp
))
583 double l
= (double)sqrt(((xp
- x
) * (xp
- x
)) +
584 ((yp
- y
) * (yp
- y
)));
589 nearest_attachment
= i
;
593 *attachment
= nearest_attachment
;
600 // Format a text string according to the region size, adding
601 // strings with positions to region text list
603 static bool GraphicsInSizeToContents
= FALSE
; // Infinite recursion elimination
604 void wxShape::FormatText(wxDC
& dc
, const wxString
& s
, int i
)
609 if (m_regions
.Number() < 1)
611 wxNode
*node
= m_regions
.Nth(i
);
615 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
617 dc
.SetFont(* region
->GetFont());
619 region
->GetSize(&w
, &h
);
621 wxStringList
*stringList
= oglFormatText(dc
, s
, (w
-5), (h
-5), region
->GetFormatMode());
622 node
= stringList
->First();
625 char *s
= (char *)node
->Data();
626 wxShapeTextLine
*line
= new wxShapeTextLine(0.0, 0.0, s
);
627 region
->GetFormattedText().Append((wxObject
*)line
);
633 // Don't try to resize an object with more than one image (this case should be dealt
634 // with by overriden handlers)
635 if ((region
->GetFormatMode() & FORMAT_SIZE_TO_CONTENTS
) &&
636 (region
->GetFormattedText().Number() > 0) &&
637 (m_regions
.Number() == 1) && !GraphicsInSizeToContents
)
639 oglGetCentredTextExtent(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, w
, h
, &actualW
, &actualH
);
640 if ((actualW
+m_textMarginX
!= w
) || (actualH
+m_textMarginY
!= h
))
642 // If we are a descendant of a composite, must make sure the composite gets
644 wxShape
*topAncestor
= GetTopAncestor();
646 if (topAncestor
!= this)
648 // Make sure we don't recurse infinitely
649 GraphicsInSizeToContents
= TRUE
;
651 wxCompositeShape
*composite
= (wxCompositeShape
*)topAncestor
;
652 composite
->Erase(dc
);
653 SetSize(actualW
+m_textMarginX
, actualH
+m_textMarginY
);
654 Move(dc
, m_xpos
, m_ypos
);
655 composite
->CalculateSize();
656 if (composite
->Selected())
658 composite
->DeleteControlPoints(& dc
);
659 composite
->MakeControlPoints();
660 composite
->MakeMandatoryControlPoints();
662 // Where infinite recursion might happen if we didn't stop it
665 GraphicsInSizeToContents
= FALSE
;
670 SetSize(actualW
+m_textMarginX
, actualH
+m_textMarginY
);
671 Move(dc
, m_xpos
, m_ypos
);
673 SetSize(actualW
+m_textMarginX
, actualH
+m_textMarginY
);
674 Move(dc
, m_xpos
, m_ypos
);
678 oglCentreText(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, actualW
, actualH
, region
->GetFormatMode());
682 void wxShape::Recentre(wxDC
& dc
)
685 GetBoundingBoxMin(&w
, &h
);
687 int noRegions
= m_regions
.Number();
688 for (int i
= 0; i
< noRegions
; i
++)
690 wxNode
*node
= m_regions
.Nth(i
);
693 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
694 oglCentreText(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, w
, h
, region
->GetFormatMode());
699 bool wxShape::GetPerimeterPoint(double x1
, double y1
,
700 double x2
, double y2
,
701 double *x3
, double *y3
)
706 void wxShape::SetPen(wxPen
*the_pen
)
711 void wxShape::SetBrush(wxBrush
*the_brush
)
716 // Get the top-most (non-division) ancestor, or self
717 wxShape
*wxShape::GetTopAncestor()
722 if (GetParent()->IsKindOf(CLASSINFO(wxDivisionShape
)))
724 else return GetParent()->GetTopAncestor();
731 void wxShape::SetFont(wxFont
*the_font
, int regionId
)
734 wxNode
*node
= m_regions
.Nth(regionId
);
737 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
738 region
->SetFont(the_font
);
741 wxFont
*wxShape::GetFont(int n
) const
743 wxNode
*node
= m_regions
.Nth(n
);
746 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
747 return region
->GetFont();
750 void wxShape::SetFormatMode(int mode
, int regionId
)
752 wxNode
*node
= m_regions
.Nth(regionId
);
755 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
756 region
->SetFormatMode(mode
);
759 int wxShape::GetFormatMode(int regionId
) const
761 wxNode
*node
= m_regions
.Nth(regionId
);
764 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
765 return region
->GetFormatMode();
768 void wxShape::SetTextColour(const wxString
& the_colour
, int regionId
)
770 wxColour
*wxcolour
= wxTheColourDatabase
->FindColour(the_colour
);
771 m_textColour
= wxcolour
;
772 m_textColourName
= the_colour
;
774 wxNode
*node
= m_regions
.Nth(regionId
);
777 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
778 region
->SetColour(the_colour
);
781 wxString
wxShape::GetTextColour(int regionId
) const
783 wxNode
*node
= m_regions
.Nth(regionId
);
786 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
787 return region
->GetColour();
790 void wxShape::SetRegionName(const wxString
& name
, int regionId
)
792 wxNode
*node
= m_regions
.Nth(regionId
);
795 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
796 region
->SetName(name
);
799 wxString
wxShape::GetRegionName(int regionId
)
801 wxNode
*node
= m_regions
.Nth(regionId
);
804 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
805 return region
->GetName();
808 int wxShape::GetRegionId(const wxString
& name
)
810 wxNode
*node
= m_regions
.First();
814 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
815 if (region
->GetName() == name
)
823 // Name all m_regions in all subimages recursively.
824 void wxShape::NameRegions(const wxString
& parentName
)
826 int n
= GetNumberOfTextRegions();
828 for (int i
= 0; i
< n
; i
++)
830 if (parentName
.Length() > 0)
831 sprintf(buf
, "%s.%d", (const char*) parentName
, i
);
833 sprintf(buf
, "%d", i
);
834 SetRegionName(buf
, i
);
836 wxNode
*node
= m_children
.First();
840 wxShape
*child
= (wxShape
*)node
->Data();
841 if (parentName
.Length() > 0)
842 sprintf(buf
, "%s.%d", (const char*) parentName
, j
);
844 sprintf(buf
, "%d", j
);
845 child
->NameRegions(buf
);
851 // Get a region by name, possibly looking recursively into composites.
852 wxShape
*wxShape::FindRegion(const wxString
& name
, int *regionId
)
854 int id
= GetRegionId(name
);
861 wxNode
*node
= m_children
.First();
864 wxShape
*child
= (wxShape
*)node
->Data();
865 wxShape
*actualImage
= child
->FindRegion(name
, regionId
);
873 // Finds all region names for this image (composite or simple).
874 // Supply empty string list.
875 void wxShape::FindRegionNames(wxStringList
& list
)
877 int n
= GetNumberOfTextRegions();
878 for (int i
= 0; i
< n
; i
++)
880 wxString
name(GetRegionName(i
));
881 list
.Add((const char*) name
);
884 wxNode
*node
= m_children
.First();
887 wxShape
*child
= (wxShape
*)node
->Data();
888 child
->FindRegionNames(list
);
893 void wxShape::AssignNewIds()
897 wxNode
*node
= m_children
.First();
900 wxShape
*child
= (wxShape
*)node
->Data();
901 child
->AssignNewIds();
906 void wxShape::OnDraw(wxDC
& dc
)
910 void wxShape::OnMoveLinks(wxDC
& dc
)
912 // Want to set the ends of all attached links
913 // to point to/from this object
915 wxNode
*current
= m_lines
.First();
918 wxLineShape
*line
= (wxLineShape
*)current
->Data();
919 line
->GetEventHandler()->OnMoveLink(dc
);
920 current
= current
->Next();
925 void wxShape::OnDrawContents(wxDC
& dc
)
927 double bound_x
, bound_y
;
928 GetBoundingBoxMin(&bound_x
, &bound_y
);
929 if (m_regions
.Number() < 1) return;
931 if (m_pen
) dc
.SetPen(* m_pen
);
933 wxShapeRegion
*region
= (wxShapeRegion
*)m_regions
.First()->Data();
934 if (region
->GetFont()) dc
.SetFont(* region
->GetFont());
936 dc
.SetTextForeground(* (region
->GetActualColourObject()));
937 dc
.SetBackgroundMode(wxTRANSPARENT
);
940 oglCentreText(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, bound_x
, bound_y
, region
->GetFormatMode());
943 if (!GetDisableLabel())
945 oglDrawFormattedText(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, bound_x
, bound_y
, region
->GetFormatMode());
949 void wxShape::DrawContents(wxDC
& dc
)
951 GetEventHandler()->OnDrawContents(dc
);
954 void wxShape::OnSize(double x
, double y
)
958 bool wxShape::OnMovePre(wxDC
& dc
, double x
, double y
, double old_x
, double old_y
, bool display
)
963 void wxShape::OnMovePost(wxDC
& dc
, double x
, double y
, double old_x
, double old_y
, bool display
)
967 void wxShape::OnErase(wxDC
& dc
)
973 wxNode
*current
= m_lines
.First();
976 wxLineShape
*line
= (wxLineShape
*)current
->Data();
977 line
->GetEventHandler()->OnErase(dc
);
978 current
= current
->Next();
980 GetEventHandler()->OnEraseContents(dc
);
983 void wxShape::OnEraseContents(wxDC
& dc
)
988 double maxX
, maxY
, minX
, minY
;
991 GetBoundingBoxMin(&minX
, &minY
);
992 GetBoundingBoxMax(&maxX
, &maxY
);
993 double topLeftX
= (double)(xp
- (maxX
/ 2.0) - 2.0);
994 double topLeftY
= (double)(yp
- (maxY
/ 2.0) - 2.0);
998 penWidth
= m_pen
->GetWidth();
1000 dc
.SetPen(* g_oglWhiteBackgroundPen
);
1001 dc
.SetBrush(* g_oglWhiteBackgroundBrush
);
1002 dc
.DrawRectangle(WXROUND(topLeftX
- penWidth
), WXROUND(topLeftY
- penWidth
),
1003 WXROUND(maxX
+ penWidth
*2.0 + 4.0), WXROUND(maxY
+ penWidth
*2.0 + 4.0));
1006 void wxShape::EraseLinks(wxDC
& dc
, int attachment
, bool recurse
)
1011 wxNode
*current
= m_lines
.First();
1014 wxLineShape
*line
= (wxLineShape
*)current
->Data();
1015 if (attachment
== -1 || ((line
->GetTo() == this && line
->GetAttachmentTo() == attachment
) ||
1016 (line
->GetFrom() == this && line
->GetAttachmentFrom() == attachment
)))
1017 line
->GetEventHandler()->OnErase(dc
);
1018 current
= current
->Next();
1022 wxNode
*node
= m_children
.First();
1025 wxShape
*child
= (wxShape
*)node
->Data();
1026 child
->EraseLinks(dc
, attachment
, recurse
);
1027 node
= node
->Next();
1032 void wxShape::DrawLinks(wxDC
& dc
, int attachment
, bool recurse
)
1037 wxNode
*current
= m_lines
.First();
1040 wxLineShape
*line
= (wxLineShape
*)current
->Data();
1041 if (attachment
== -1 ||
1042 (line
->GetTo() == this && line
->GetAttachmentTo() == attachment
) ||
1043 (line
->GetFrom() == this && line
->GetAttachmentFrom() == attachment
))
1045 current
= current
->Next();
1049 wxNode
*node
= m_children
.First();
1052 wxShape
*child
= (wxShape
*)node
->Data();
1053 child
->DrawLinks(dc
, attachment
, recurse
);
1054 node
= node
->Next();
1059 // Returns TRUE if pt1 <= pt2 in the sense that one point comes before another on an
1060 // edge of the shape.
1061 // attachmentPoint is the attachment point (= side) in question.
1063 // This is the default, rectangular implementation.
1064 bool wxShape::AttachmentSortTest(int attachmentPoint
, const wxRealPoint
& pt1
, const wxRealPoint
& pt2
)
1066 int physicalAttachment
= LogicalToPhysicalAttachment(attachmentPoint
);
1067 switch (physicalAttachment
)
1072 return (pt1
.x
<= pt2
.x
) ;
1078 return (pt1
.y
<= pt2
.y
) ;
1086 bool wxShape::MoveLineToNewAttachment(wxDC
& dc
, wxLineShape
*to_move
,
1089 if (GetAttachmentMode() == ATTACHMENT_MODE_NONE
)
1092 int newAttachment
, oldAttachment
;
1095 // Is (x, y) on this object? If so, find the new attachment point
1096 // the user has moved the point to
1097 bool hit
= HitTest(x
, y
, &newAttachment
, &distance
);
1103 if (to_move
->GetTo() == this)
1104 oldAttachment
= to_move
->GetAttachmentTo();
1106 oldAttachment
= to_move
->GetAttachmentFrom();
1108 // The links in a new ordering.
1111 // First, add all links to the new list.
1112 wxNode
*node
= m_lines
.First();
1115 newOrdering
.Append(node
->Data());
1116 node
= node
->Next();
1119 // Delete the line object from the list of links; we're going to move
1120 // it to another position in the list
1121 newOrdering
.DeleteObject(to_move
);
1123 double old_x
= (double) -99999.9;
1124 double old_y
= (double) -99999.9;
1126 node
= newOrdering
.First();
1129 while (!found
&& node
)
1131 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1132 if ((line
->GetTo() == this && oldAttachment
== line
->GetAttachmentTo()) ||
1133 (line
->GetFrom() == this && oldAttachment
== line
->GetAttachmentFrom()))
1135 double startX
, startY
, endX
, endY
;
1137 line
->GetEnds(&startX
, &startY
, &endX
, &endY
);
1138 if (line
->GetTo() == this)
1148 wxRealPoint
thisPoint(xp
, yp
);
1149 wxRealPoint
lastPoint(old_x
, old_y
);
1150 wxRealPoint
newPoint(x
, y
);
1152 if (AttachmentSortTest(newAttachment
, newPoint
, thisPoint
) && AttachmentSortTest(newAttachment
, lastPoint
, newPoint
))
1155 newOrdering
.Insert(node
, to_move
);
1161 node
= node
->Next();
1165 newOrdering
.Append(to_move
);
1167 GetEventHandler()->OnChangeAttachment(newAttachment
, to_move
, newOrdering
);
1172 void wxShape::OnChangeAttachment(int attachment
, wxLineShape
* line
, wxList
& ordering
)
1174 if (line
->GetTo() == this)
1175 line
->SetAttachmentTo(attachment
);
1177 line
->SetAttachmentFrom(attachment
);
1179 ApplyAttachmentOrdering(ordering
);
1181 wxClientDC
dc(GetCanvas());
1182 GetCanvas()->PrepareDC(dc
);
1186 if (!GetCanvas()->GetQuickEditMode()) GetCanvas()->Redraw(dc
);
1189 // Reorders the lines according to the given list.
1190 void wxShape::ApplyAttachmentOrdering(wxList
& linesToSort
)
1192 // This is a temporary store of all the lines.
1195 wxNode
*node
= m_lines
.First();
1198 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1199 linesStore
.Append(line
);
1200 node
= node
->Next();;
1205 node
= linesToSort
.First();
1208 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1209 if (linesStore
.Member(line
))
1212 linesStore
.DeleteObject(line
);
1213 m_lines
.Append(line
);
1215 node
= node
->Next();
1218 // Now add any lines that haven't been listed in linesToSort.
1219 node
= linesStore
.First();
1222 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1223 m_lines
.Append(line
);
1224 node
= node
->Next();
1228 // Reorders the lines coming into the node image at this attachment
1229 // position, in the order in which they appear in linesToSort.
1230 // Any remaining lines not in the list will be added to the end.
1231 void wxShape::SortLines(int attachment
, wxList
& linesToSort
)
1233 // This is a temporary store of all the lines at this attachment
1234 // point. We'll tick them off as we've processed them.
1235 wxList linesAtThisAttachment
;
1237 wxNode
*node
= m_lines
.First();
1240 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1241 wxNode
*next
= node
->Next();
1242 if ((line
->GetTo() == this && line
->GetAttachmentTo() == attachment
) ||
1243 (line
->GetFrom() == this && line
->GetAttachmentFrom() == attachment
))
1245 linesAtThisAttachment
.Append(line
);
1249 else node
= node
->Next();
1252 node
= linesToSort
.First();
1255 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1256 if (linesAtThisAttachment
.Member(line
))
1259 linesAtThisAttachment
.DeleteObject(line
);
1260 m_lines
.Append(line
);
1262 node
= node
->Next();
1265 // Now add any lines that haven't been listed in linesToSort.
1266 node
= linesAtThisAttachment
.First();
1269 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1270 m_lines
.Append(line
);
1271 node
= node
->Next();
1275 void wxShape::OnHighlight(wxDC
& dc
)
1279 void wxShape::OnLeftClick(double x
, double y
, int keys
, int attachment
)
1281 if ((m_sensitivity
& OP_CLICK_LEFT
) != OP_CLICK_LEFT
)
1287 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1288 m_parent
->GetEventHandler()->OnLeftClick(x
, y
, keys
, attachment
);
1294 void wxShape::OnRightClick(double x
, double y
, int keys
, int attachment
)
1296 if ((m_sensitivity
& OP_CLICK_RIGHT
) != OP_CLICK_RIGHT
)
1302 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1303 m_parent
->GetEventHandler()->OnRightClick(x
, y
, keys
, attachment
);
1309 double DragOffsetX
= 0.0;
1310 double DragOffsetY
= 0.0;
1312 void wxShape::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
1314 if ((m_sensitivity
& OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
1320 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1321 m_parent
->GetEventHandler()->OnDragLeft(draw
, x
, y
, keys
, attachment
);
1326 wxClientDC
dc(GetCanvas());
1327 GetCanvas()->PrepareDC(dc
);
1329 dc
.SetLogicalFunction(OGLRBLF
);
1331 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1332 dc
.SetPen(dottedPen
);
1333 dc
.SetBrush(* wxTRANSPARENT_BRUSH
);
1336 xx
= x
+ DragOffsetX
;
1337 yy
= y
+ DragOffsetY
;
1339 m_canvas
->Snap(&xx
, &yy
);
1340 // m_xpos = xx; m_ypos = yy;
1342 GetBoundingBoxMax(&w
, &h
);
1343 GetEventHandler()->OnDrawOutline(dc
, xx
, yy
, w
, h
);
1346 void wxShape::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
1348 if ((m_sensitivity
& OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
1354 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1355 m_parent
->GetEventHandler()->OnBeginDragLeft(x
, y
, keys
, attachment
);
1360 DragOffsetX
= m_xpos
- x
;
1361 DragOffsetY
= m_ypos
- y
;
1363 wxClientDC
dc(GetCanvas());
1364 GetCanvas()->PrepareDC(dc
);
1366 // New policy: don't erase shape until end of drag.
1370 xx
= x
+ DragOffsetX
;
1371 yy
= y
+ DragOffsetY
;
1372 m_canvas
->Snap(&xx
, &yy
);
1373 // m_xpos = xx; m_ypos = yy;
1374 dc
.SetLogicalFunction(OGLRBLF
);
1376 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1377 dc
.SetPen(dottedPen
);
1378 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1381 GetBoundingBoxMax(&w
, &h
);
1382 GetEventHandler()->OnDrawOutline(dc
, xx
, yy
, w
, h
);
1383 m_canvas
->CaptureMouse();
1386 void wxShape::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
1388 m_canvas
->ReleaseMouse();
1389 if ((m_sensitivity
& OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
1395 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1396 m_parent
->GetEventHandler()->OnEndDragLeft(x
, y
, keys
, attachment
);
1401 wxClientDC
dc(GetCanvas());
1402 GetCanvas()->PrepareDC(dc
);
1404 dc
.SetLogicalFunction(wxCOPY
);
1406 double xx
= x
+ DragOffsetX
;
1407 double yy
= y
+ DragOffsetY
;
1408 m_canvas
->Snap(&xx
, &yy
);
1409 // canvas->Snap(&m_xpos, &m_ypos);
1411 // New policy: erase shape at end of drag.
1415 if (m_canvas
&& !m_canvas
->GetQuickEditMode()) m_canvas
->Redraw(dc
);
1418 void wxShape::OnDragRight(bool draw
, double x
, double y
, int keys
, int attachment
)
1420 if ((m_sensitivity
& OP_DRAG_RIGHT
) != OP_DRAG_RIGHT
)
1426 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1427 m_parent
->GetEventHandler()->OnDragRight(draw
, x
, y
, keys
, attachment
);
1433 void wxShape::OnBeginDragRight(double x
, double y
, int keys
, int attachment
)
1435 if ((m_sensitivity
& OP_DRAG_RIGHT
) != OP_DRAG_RIGHT
)
1441 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1442 m_parent
->GetEventHandler()->OnBeginDragRight(x
, y
, keys
, attachment
);
1448 void wxShape::OnEndDragRight(double x
, double y
, int keys
, int attachment
)
1450 if ((m_sensitivity
& OP_DRAG_RIGHT
) != OP_DRAG_RIGHT
)
1456 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1457 m_parent
->GetEventHandler()->OnEndDragRight(x
, y
, keys
, attachment
);
1463 void wxShape::OnDrawOutline(wxDC
& dc
, double x
, double y
, double w
, double h
)
1465 double top_left_x
= (double)(x
- w
/2.0);
1466 double top_left_y
= (double)(y
- h
/2.0);
1467 double top_right_x
= (double)(top_left_x
+ w
);
1468 double top_right_y
= (double)top_left_y
;
1469 double bottom_left_x
= (double)top_left_x
;
1470 double bottom_left_y
= (double)(top_left_y
+ h
);
1471 double bottom_right_x
= (double)top_right_x
;
1472 double bottom_right_y
= (double)bottom_left_y
;
1475 points
[0].x
= WXROUND(top_left_x
); points
[0].y
= WXROUND(top_left_y
);
1476 points
[1].x
= WXROUND(top_right_x
); points
[1].y
= WXROUND(top_right_y
);
1477 points
[2].x
= WXROUND(bottom_right_x
); points
[2].y
= WXROUND(bottom_right_y
);
1478 points
[3].x
= WXROUND(bottom_left_x
); points
[3].y
= WXROUND(bottom_left_y
);
1479 points
[4].x
= WXROUND(top_left_x
); points
[4].y
= WXROUND(top_left_y
);
1481 dc
.DrawLines(5, points
);
1484 void wxShape::Attach(wxShapeCanvas
*can
)
1489 void wxShape::Detach()
1494 void wxShape::Move(wxDC
& dc
, double x
, double y
, bool display
)
1496 double old_x
= m_xpos
;
1497 double old_y
= m_ypos
;
1499 if (!GetEventHandler()->OnMovePre(dc
, x
, y
, old_x
, old_y
, display
))
1506 m_xpos
= x
; m_ypos
= y
;
1508 ResetControlPoints();
1515 GetEventHandler()->OnMovePost(dc
, x
, y
, old_x
, old_y
, display
);
1518 void wxShape::MoveLinks(wxDC
& dc
)
1520 GetEventHandler()->OnMoveLinks(dc
);
1524 void wxShape::Draw(wxDC
& dc
)
1528 GetEventHandler()->OnDraw(dc
);
1529 GetEventHandler()->OnDrawContents(dc
);
1530 GetEventHandler()->OnDrawControlPoints(dc
);
1531 GetEventHandler()->OnDrawBranches(dc
);
1535 void wxShape::Flash()
1539 wxClientDC
dc(GetCanvas());
1540 GetCanvas()->PrepareDC(dc
);
1542 dc
.SetLogicalFunction(OGLRBLF
);
1544 dc
.SetLogicalFunction(wxCOPY
);
1549 void wxShape::Show(bool show
)
1552 wxNode
*node
= m_children
.First();
1555 wxShape
*image
= (wxShape
*)node
->Data();
1557 node
= node
->Next();
1561 void wxShape::Erase(wxDC
& dc
)
1563 GetEventHandler()->OnErase(dc
);
1564 GetEventHandler()->OnEraseControlPoints(dc
);
1565 GetEventHandler()->OnDrawBranches(dc
, TRUE
);
1568 void wxShape::EraseContents(wxDC
& dc
)
1570 GetEventHandler()->OnEraseContents(dc
);
1573 void wxShape::AddText(const wxString
& string
)
1575 wxNode
*node
= m_regions
.First();
1578 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
1579 region
->ClearText();
1580 wxShapeTextLine
*new_line
=
1581 new wxShapeTextLine(0.0, 0.0, string
);
1582 region
->GetFormattedText().Append(new_line
);
1584 m_formatted
= FALSE
;
1587 void wxShape::SetSize(double x
, double y
, bool recursive
)
1589 SetAttachmentSize(x
, y
);
1590 SetDefaultRegionSize();
1593 void wxShape::SetAttachmentSize(double w
, double h
)
1597 double width
, height
;
1598 GetBoundingBoxMin(&width
, &height
);
1601 else scaleX
= w
/width
;
1604 else scaleY
= h
/height
;
1606 wxNode
*node
= m_attachmentPoints
.First();
1609 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
1610 point
->m_x
= (double)(point
->m_x
* scaleX
);
1611 point
->m_y
= (double)(point
->m_y
* scaleY
);
1612 node
= node
->Next();
1616 // Add line FROM this object
1617 void wxShape::AddLine(wxLineShape
*line
, wxShape
*other
,
1618 int attachFrom
, int attachTo
,
1619 // The line ordering
1620 int positionFrom
, int positionTo
)
1622 if (positionFrom
== -1)
1624 if (!m_lines
.Member(line
))
1625 m_lines
.Append(line
);
1629 // Don't preserve old ordering if we have new ordering instructions
1630 m_lines
.DeleteObject(line
);
1631 if (positionFrom
< m_lines
.Number())
1633 wxNode
* node
= m_lines
.Nth(positionFrom
);
1634 m_lines
.Insert(node
, line
);
1637 m_lines
.Append(line
);
1640 if (positionTo
== -1)
1642 if (!other
->m_lines
.Member(line
))
1643 other
->m_lines
.Append(line
);
1647 // Don't preserve old ordering if we have new ordering instructions
1648 other
->m_lines
.DeleteObject(line
);
1649 if (positionTo
< other
->m_lines
.Number())
1651 wxNode
* node
= other
->m_lines
.Nth(positionTo
);
1652 other
->m_lines
.Insert(node
, line
);
1655 other
->m_lines
.Append(line
);
1658 // Wrong: doesn't preserve ordering of shape already linked
1659 m_lines
.DeleteObject(line
);
1660 other
->m_lines
.DeleteObject(line
);
1662 if (positionFrom
== -1)
1663 m_lines
.Append(line
);
1666 if (positionFrom
< m_lines
.Number())
1668 wxNode
* node
= m_lines
.Nth(positionFrom
);
1669 m_lines
.Insert(node
, line
);
1672 m_lines
.Append(line
);
1675 if (positionTo
== -1)
1676 other
->m_lines
.Append(line
);
1679 if (positionTo
< other
->m_lines
.Number())
1681 wxNode
* node
= other
->m_lines
.Nth(positionTo
);
1682 other
->m_lines
.Insert(node
, line
);
1685 other
->m_lines
.Append(line
);
1689 line
->SetFrom(this);
1691 line
->SetAttachments(attachFrom
, attachTo
);
1694 void wxShape::RemoveLine(wxLineShape
*line
)
1696 if (line
->GetFrom() == this)
1697 line
->GetTo()->m_lines
.DeleteObject(line
);
1699 line
->GetFrom()->m_lines
.DeleteObject(line
);
1701 m_lines
.DeleteObject(line
);
1705 void wxShape::WriteAttributes(wxExpr
*clause
)
1707 clause
->AddAttributeValueString("type", GetClassInfo()->GetClassName());
1708 clause
->AddAttributeValue("id", m_id
);
1712 int penWidth
= m_pen
->GetWidth();
1713 int penStyle
= m_pen
->GetStyle();
1715 clause
->AddAttributeValue("pen_width", (long)penWidth
);
1716 if (penStyle
!= wxSOLID
)
1717 clause
->AddAttributeValue("pen_style", (long)penStyle
);
1719 wxString penColour
= wxTheColourDatabase
->FindName(m_pen
->GetColour());
1720 if (penColour
== "")
1722 wxString
hex(oglColourToHex(m_pen
->GetColour()));
1723 hex
= wxString("#") + hex
;
1724 clause
->AddAttributeValueString("pen_colour", hex
);
1726 else if (penColour
!= "BLACK")
1727 clause
->AddAttributeValueString("pen_colour", penColour
);
1732 wxString brushColour
= wxTheColourDatabase
->FindName(m_brush
->GetColour());
1734 if (brushColour
== "")
1736 wxString
hex(oglColourToHex(m_brush
->GetColour()));
1737 hex
= wxString("#") + hex
;
1738 clause
->AddAttributeValueString("brush_colour", hex
);
1740 else if (brushColour
!= "WHITE")
1741 clause
->AddAttributeValueString("brush_colour", brushColour
);
1743 if (m_brush
->GetStyle() != wxSOLID
)
1744 clause
->AddAttributeValue("brush_style", (long)m_brush
->GetStyle());
1749 int n_lines
= m_lines
.Number();
1752 wxExpr
*list
= new wxExpr(wxExprList
);
1753 wxNode
*node
= m_lines
.First();
1756 wxShape
*line
= (wxShape
*)node
->Data();
1757 wxExpr
*id_expr
= new wxExpr(line
->GetId());
1758 list
->Append(id_expr
);
1759 node
= node
->Next();
1761 clause
->AddAttributeValue("arcs", list
);
1764 // Miscellaneous members
1765 if (m_attachmentMode
!= 0)
1766 clause
->AddAttributeValue("use_attachments", (long)m_attachmentMode
);
1767 if (m_sensitivity
!= OP_ALL
)
1768 clause
->AddAttributeValue("sensitivity", (long)m_sensitivity
);
1769 if (!m_spaceAttachments
)
1770 clause
->AddAttributeValue("space_attachments", (long)m_spaceAttachments
);
1772 clause
->AddAttributeValue("fixed_width", (long)m_fixedWidth
);
1774 clause
->AddAttributeValue("fixed_height", (long)m_fixedHeight
);
1775 if (m_shadowMode
!= SHADOW_NONE
)
1776 clause
->AddAttributeValue("shadow_mode", (long)m_shadowMode
);
1777 if (m_centreResize
!= TRUE
)
1778 clause
->AddAttributeValue("centre_resize", (long)0);
1779 clause
->AddAttributeValue("maintain_aspect_ratio", (long) m_maintainAspectRatio
);
1780 if (m_highlighted
!= FALSE
)
1781 clause
->AddAttributeValue("hilite", (long)m_highlighted
);
1783 if (m_parent
) // For composite objects
1784 clause
->AddAttributeValue("parent", (long)m_parent
->GetId());
1786 if (m_rotation
!= 0.0)
1787 clause
->AddAttributeValue("rotation", m_rotation
);
1789 if (!this->IsKindOf(CLASSINFO(wxLineShape
)))
1791 clause
->AddAttributeValue("neck_length", (long) m_branchNeckLength
);
1792 clause
->AddAttributeValue("stem_length", (long) m_branchStemLength
);
1793 clause
->AddAttributeValue("branch_spacing", (long) m_branchSpacing
);
1794 clause
->AddAttributeValue("branch_style", (long) m_branchStyle
);
1797 // Write user-defined attachment points, if any
1798 if (m_attachmentPoints
.Number() > 0)
1800 wxExpr
*attachmentList
= new wxExpr(wxExprList
);
1801 wxNode
*node
= m_attachmentPoints
.First();
1804 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
1805 wxExpr
*pointExpr
= new wxExpr(wxExprList
);
1806 pointExpr
->Append(new wxExpr((long)point
->m_id
));
1807 pointExpr
->Append(new wxExpr(point
->m_x
));
1808 pointExpr
->Append(new wxExpr(point
->m_y
));
1809 attachmentList
->Append(pointExpr
);
1810 node
= node
->Next();
1812 clause
->AddAttributeValue("user_attachments", attachmentList
);
1815 // Write text regions
1816 WriteRegions(clause
);
1819 void wxShape::WriteRegions(wxExpr
*clause
)
1821 // Output regions as region1 = (...), region2 = (...), etc
1822 // and formatted text as text1 = (...), text2 = (...) etc.
1824 char regionNameBuf
[20];
1825 char textNameBuf
[20];
1826 wxNode
*node
= m_regions
.First();
1829 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
1830 sprintf(regionNameBuf
, "region%d", regionNo
);
1831 sprintf(textNameBuf
, "text%d", regionNo
);
1833 // Original text and region attributes:
1834 // region1 = (regionName regionText x y width height minWidth minHeight proportionX proportionY
1835 // formatMode fontSize fontFamily fontStyle fontWeight textColour)
1836 wxExpr
*regionExpr
= new wxExpr(wxExprList
);
1837 regionExpr
->Append(new wxExpr(wxExprString
, region
->m_regionName
));
1838 regionExpr
->Append(new wxExpr(wxExprString
, region
->m_regionText
));
1840 regionExpr
->Append(new wxExpr(region
->m_x
));
1841 regionExpr
->Append(new wxExpr(region
->m_y
));
1842 regionExpr
->Append(new wxExpr(region
->GetWidth()));
1843 regionExpr
->Append(new wxExpr(region
->GetHeight()));
1845 regionExpr
->Append(new wxExpr(region
->m_minWidth
));
1846 regionExpr
->Append(new wxExpr(region
->m_minHeight
));
1847 regionExpr
->Append(new wxExpr(region
->m_regionProportionX
));
1848 regionExpr
->Append(new wxExpr(region
->m_regionProportionY
));
1850 regionExpr
->Append(new wxExpr((long)region
->m_formatMode
));
1852 regionExpr
->Append(new wxExpr((long)(region
->m_font
? region
->m_font
->GetPointSize() : 10)));
1853 regionExpr
->Append(new wxExpr((long)(region
->m_font
? region
->m_font
->GetFamily() : wxDEFAULT
)));
1854 regionExpr
->Append(new wxExpr((long)(region
->m_font
? region
->m_font
->GetStyle() : wxDEFAULT
)));
1855 regionExpr
->Append(new wxExpr((long)(region
->m_font
? region
->m_font
->GetWeight() : wxNORMAL
)));
1856 regionExpr
->Append(new wxExpr(wxExprString
, region
->m_textColour
));
1858 // New members for pen colour/style
1859 regionExpr
->Append(new wxExpr(wxExprString
, region
->m_penColour
));
1860 regionExpr
->Append(new wxExpr((long)region
->m_penStyle
));
1863 // text1 = ((x y string) (x y string) ...)
1864 wxExpr
*textExpr
= new wxExpr(wxExprList
);
1866 wxNode
*textNode
= region
->m_formattedText
.First();
1869 wxShapeTextLine
*line
= (wxShapeTextLine
*)textNode
->Data();
1870 wxExpr
*list2
= new wxExpr(wxExprList
);
1871 list2
->Append(new wxExpr(line
->GetX()));
1872 list2
->Append(new wxExpr(line
->GetY()));
1873 list2
->Append(new wxExpr(wxExprString
, line
->GetText()));
1874 textExpr
->Append(list2
);
1875 textNode
= textNode
->Next();
1878 // Now add both attributes to the clause
1879 clause
->AddAttributeValue(regionNameBuf
, regionExpr
);
1880 clause
->AddAttributeValue(textNameBuf
, textExpr
);
1882 node
= node
->Next();
1887 void wxShape::ReadAttributes(wxExpr
*clause
)
1889 clause
->GetAttributeValue("id", m_id
);
1892 clause
->GetAttributeValue("x", m_xpos
);
1893 clause
->GetAttributeValue("y", m_ypos
);
1895 // Input text strings (FOR COMPATIBILITY WITH OLD FILES ONLY. SEE REGION CODE BELOW.)
1897 wxExpr
*strings
= clause
->AttributeValue("text");
1898 if (strings
&& strings
->Type() == wxExprList
)
1900 m_formatted
= TRUE
; // Assume text is formatted unless we prove otherwise
1901 wxExpr
*node
= strings
->value
.first
;
1904 wxExpr
*string_expr
= node
;
1907 wxString
the_string("");
1909 // string_expr can either be a string, or a list of
1910 // 3 elements: x, y, and string.
1911 if (string_expr
->Type() == wxExprString
)
1913 the_string
= string_expr
->StringValue();
1914 m_formatted
= FALSE
;
1916 else if (string_expr
->Type() == wxExprList
)
1918 wxExpr
*first
= string_expr
->value
.first
;
1919 wxExpr
*second
= first
? first
->next
: (wxExpr
*) NULL
;
1920 wxExpr
*third
= second
? second
->next
: (wxExpr
*) NULL
;
1922 if (first
&& second
&& third
&&
1923 (first
->Type() == wxExprReal
|| first
->Type() == wxExprInteger
) &&
1924 (second
->Type() == wxExprReal
|| second
->Type() == wxExprInteger
) &&
1925 third
->Type() == wxExprString
)
1927 if (first
->Type() == wxExprReal
)
1928 the_x
= first
->RealValue();
1929 else the_x
= (double)first
->IntegerValue();
1931 if (second
->Type() == wxExprReal
)
1932 the_y
= second
->RealValue();
1933 else the_y
= (double)second
->IntegerValue();
1935 the_string
= third
->StringValue();
1938 wxShapeTextLine
*line
=
1939 new wxShapeTextLine(the_x
, the_y
, (char*) (const char*) the_string
);
1940 m_text
.Append(line
);
1946 wxString pen_string
= "";
1947 wxString brush_string
= "";
1949 int pen_style
= wxSOLID
;
1950 int brush_style
= wxSOLID
;
1951 m_attachmentMode
= ATTACHMENT_MODE_NONE
;
1953 clause
->GetAttributeValue("pen_colour", pen_string
);
1954 clause
->GetAttributeValue("text_colour", m_textColourName
);
1956 SetTextColour(m_textColourName
);
1958 clause
->GetAttributeValue("region_name", m_regionName
);
1960 clause
->GetAttributeValue("brush_colour", brush_string
);
1961 clause
->GetAttributeValue("pen_width", pen_width
);
1962 clause
->GetAttributeValue("pen_style", pen_style
);
1963 clause
->GetAttributeValue("brush_style", brush_style
);
1965 int iVal
= (int) m_attachmentMode
;
1966 clause
->GetAttributeValue("use_attachments", iVal
);
1967 m_attachmentMode
= iVal
;
1969 clause
->GetAttributeValue("sensitivity", m_sensitivity
);
1971 iVal
= (int) m_spaceAttachments
;
1972 clause
->GetAttributeValue("space_attachments", iVal
);
1973 m_spaceAttachments
= (iVal
!= 0);
1975 iVal
= (int) m_fixedWidth
;
1976 clause
->GetAttributeValue("fixed_width", iVal
);
1977 m_fixedWidth
= (iVal
!= 0);
1979 iVal
= (int) m_fixedHeight
;
1980 clause
->GetAttributeValue("fixed_height", iVal
);
1981 m_fixedHeight
= (iVal
!= 0);
1983 clause
->GetAttributeValue("format_mode", m_formatMode
);
1984 clause
->GetAttributeValue("shadow_mode", m_shadowMode
);
1986 iVal
= m_branchNeckLength
;
1987 clause
->GetAttributeValue("neck_length", iVal
);
1988 m_branchNeckLength
= iVal
;
1990 iVal
= m_branchStemLength
;
1991 clause
->GetAttributeValue("stem_length", iVal
);
1992 m_branchStemLength
= iVal
;
1994 iVal
= m_branchSpacing
;
1995 clause
->GetAttributeValue("branch_spacing", iVal
);
1996 m_branchSpacing
= iVal
;
1998 clause
->GetAttributeValue("branch_style", m_branchStyle
);
2000 iVal
= (int) m_centreResize
;
2001 clause
->GetAttributeValue("centre_resize", iVal
);
2002 m_centreResize
= (iVal
!= 0);
2004 iVal
= (int) m_maintainAspectRatio
;
2005 clause
->GetAttributeValue("maintain_aspect_ratio", iVal
);
2006 m_maintainAspectRatio
= (iVal
!= 0);
2008 iVal
= (int) m_highlighted
;
2009 clause
->GetAttributeValue("hilite", iVal
);
2010 m_highlighted
= (iVal
!= 0);
2012 clause
->GetAttributeValue("rotation", m_rotation
);
2014 if (pen_string
== "")
2015 pen_string
= "BLACK";
2016 if (brush_string
== "")
2017 brush_string
= "WHITE";
2019 if (pen_string
.GetChar(0) == '#')
2021 wxColour
col(oglHexToColour(pen_string
.After('#')));
2022 m_pen
= wxThePenList
->FindOrCreatePen(col
, pen_width
, pen_style
);
2025 m_pen
= wxThePenList
->FindOrCreatePen(pen_string
, pen_width
, pen_style
);
2028 m_pen
= wxBLACK_PEN
;
2030 if (brush_string
.GetChar(0) == '#')
2032 wxColour
col(oglHexToColour(brush_string
.After('#')));
2033 m_brush
= wxTheBrushList
->FindOrCreateBrush(col
, brush_style
);
2036 m_brush
= wxTheBrushList
->FindOrCreateBrush(brush_string
, brush_style
);
2039 m_brush
= wxWHITE_BRUSH
;
2041 int point_size
= 10;
2042 clause
->GetAttributeValue("point_size", point_size
);
2043 SetFont(oglMatchFont(point_size
));
2045 // Read user-defined attachment points, if any
2046 wxExpr
*attachmentList
= clause
->AttributeValue("user_attachments");
2049 wxExpr
*pointExpr
= attachmentList
->GetFirst();
2052 wxExpr
*idExpr
= pointExpr
->Nth(0);
2053 wxExpr
*xExpr
= pointExpr
->Nth(1);
2054 wxExpr
*yExpr
= pointExpr
->Nth(2);
2055 if (idExpr
&& xExpr
&& yExpr
)
2057 wxAttachmentPoint
*point
= new wxAttachmentPoint
;
2058 point
->m_id
= (int)idExpr
->IntegerValue();
2059 point
->m_x
= xExpr
->RealValue();
2060 point
->m_y
= yExpr
->RealValue();
2061 m_attachmentPoints
.Append((wxObject
*)point
);
2063 pointExpr
= pointExpr
->GetNext();
2067 // Read text regions
2068 ReadRegions(clause
);
2071 void wxShape::ReadRegions(wxExpr
*clause
)
2075 // region1 = (regionName regionText x y width height minWidth minHeight proportionX proportionY
2076 // formatMode fontSize fontFamily fontStyle fontWeight textColour)
2078 char regionNameBuf
[20];
2079 char textNameBuf
[20];
2081 wxExpr
*regionExpr
= NULL
;
2082 wxExpr
*textExpr
= NULL
;
2083 sprintf(regionNameBuf
, "region%d", regionNo
);
2084 sprintf(textNameBuf
, "text%d", regionNo
);
2086 m_formatted
= TRUE
; // Assume text is formatted unless we prove otherwise
2088 while ((regionExpr
= clause
->AttributeValue(regionNameBuf
)))
2091 * Get the region information
2095 wxString
regionName("");
2096 wxString
regionText("");
2100 double height
= 0.0;
2101 double minWidth
= 5.0;
2102 double minHeight
= 5.0;
2103 double m_regionProportionX
= -1.0;
2104 double m_regionProportionY
= -1.0;
2105 int formatMode
= FORMAT_NONE
;
2107 int fontFamily
= wxSWISS
;
2108 int fontStyle
= wxNORMAL
;
2109 int fontWeight
= wxNORMAL
;
2110 wxString
regionTextColour("");
2111 wxString
penColour("");
2112 int penStyle
= wxSOLID
;
2114 if (regionExpr
->Type() == wxExprList
)
2116 wxExpr
*nameExpr
= regionExpr
->Nth(0);
2117 wxExpr
*textExpr
= regionExpr
->Nth(1);
2118 wxExpr
*xExpr
= regionExpr
->Nth(2);
2119 wxExpr
*yExpr
= regionExpr
->Nth(3);
2120 wxExpr
*widthExpr
= regionExpr
->Nth(4);
2121 wxExpr
*heightExpr
= regionExpr
->Nth(5);
2122 wxExpr
*minWidthExpr
= regionExpr
->Nth(6);
2123 wxExpr
*minHeightExpr
= regionExpr
->Nth(7);
2124 wxExpr
*propXExpr
= regionExpr
->Nth(8);
2125 wxExpr
*propYExpr
= regionExpr
->Nth(9);
2126 wxExpr
*formatExpr
= regionExpr
->Nth(10);
2127 wxExpr
*sizeExpr
= regionExpr
->Nth(11);
2128 wxExpr
*familyExpr
= regionExpr
->Nth(12);
2129 wxExpr
*styleExpr
= regionExpr
->Nth(13);
2130 wxExpr
*weightExpr
= regionExpr
->Nth(14);
2131 wxExpr
*colourExpr
= regionExpr
->Nth(15);
2132 wxExpr
*penColourExpr
= regionExpr
->Nth(16);
2133 wxExpr
*penStyleExpr
= regionExpr
->Nth(17);
2135 regionName
= nameExpr
->StringValue();
2136 regionText
= textExpr
->StringValue();
2138 x
= xExpr
->RealValue();
2139 y
= yExpr
->RealValue();
2141 width
= widthExpr
->RealValue();
2142 height
= heightExpr
->RealValue();
2144 minWidth
= minWidthExpr
->RealValue();
2145 minHeight
= minHeightExpr
->RealValue();
2147 m_regionProportionX
= propXExpr
->RealValue();
2148 m_regionProportionY
= propYExpr
->RealValue();
2150 formatMode
= (int) formatExpr
->IntegerValue();
2151 fontSize
= (int)sizeExpr
->IntegerValue();
2152 fontFamily
= (int)familyExpr
->IntegerValue();
2153 fontStyle
= (int)styleExpr
->IntegerValue();
2154 fontWeight
= (int)weightExpr
->IntegerValue();
2158 regionTextColour
= colourExpr
->StringValue();
2161 regionTextColour
= "BLACK";
2164 penColour
= penColourExpr
->StringValue();
2166 penStyle
= (int)penStyleExpr
->IntegerValue();
2168 wxFont
*font
= wxTheFontList
->FindOrCreateFont(fontSize
, fontFamily
, fontStyle
, fontWeight
);
2170 wxShapeRegion
*region
= new wxShapeRegion
;
2171 region
->SetProportions(m_regionProportionX
, m_regionProportionY
);
2172 region
->SetFont(font
);
2173 region
->SetSize(width
, height
);
2174 region
->SetPosition(x
, y
);
2175 region
->SetMinSize(minWidth
, minHeight
);
2176 region
->SetFormatMode(formatMode
);
2177 region
->SetPenStyle(penStyle
);
2178 if (penColour
!= "")
2179 region
->SetPenColour(penColour
);
2181 region
->m_textColour
= regionTextColour
;
2182 region
->m_regionText
= regionText
;
2183 region
->m_regionName
= regionName
;
2185 m_regions
.Append(region
);
2188 * Get the formatted text strings
2191 textExpr
= clause
->AttributeValue(textNameBuf
);
2192 if (textExpr
&& (textExpr
->Type() == wxExprList
))
2194 wxExpr
*node
= textExpr
->value
.first
;
2197 wxExpr
*string_expr
= node
;
2200 wxString
the_string("");
2202 // string_expr can either be a string, or a list of
2203 // 3 elements: x, y, and string.
2204 if (string_expr
->Type() == wxExprString
)
2206 the_string
= string_expr
->StringValue();
2207 m_formatted
= FALSE
;
2209 else if (string_expr
->Type() == wxExprList
)
2211 wxExpr
*first
= string_expr
->value
.first
;
2212 wxExpr
*second
= first
? first
->next
: (wxExpr
*) NULL
;
2213 wxExpr
*third
= second
? second
->next
: (wxExpr
*) NULL
;
2215 if (first
&& second
&& third
&&
2216 (first
->Type() == wxExprReal
|| first
->Type() == wxExprInteger
) &&
2217 (second
->Type() == wxExprReal
|| second
->Type() == wxExprInteger
) &&
2218 third
->Type() == wxExprString
)
2220 if (first
->Type() == wxExprReal
)
2221 the_x
= first
->RealValue();
2222 else the_x
= (double)first
->IntegerValue();
2224 if (second
->Type() == wxExprReal
)
2225 the_y
= second
->RealValue();
2226 else the_y
= (double)second
->IntegerValue();
2228 the_string
= third
->StringValue();
2233 wxShapeTextLine
*line
=
2234 new wxShapeTextLine(the_x
, the_y
, (char*) (const char*) the_string
);
2235 region
->m_formattedText
.Append(line
);
2242 sprintf(regionNameBuf
, "region%d", regionNo
);
2243 sprintf(textNameBuf
, "text%d", regionNo
);
2246 // Compatibility: check for no regions (old file).
2247 // Lines and divided rectangles must deal with this compatibility
2248 // theirselves. Composites _may_ not have any regions anyway.
2249 if ((m_regions
.Number() == 0) &&
2250 !this->IsKindOf(CLASSINFO(wxLineShape
)) && !this->IsKindOf(CLASSINFO(wxDividedShape
)) &&
2251 !this->IsKindOf(CLASSINFO(wxCompositeShape
)))
2253 wxShapeRegion
*newRegion
= new wxShapeRegion
;
2254 newRegion
->SetName("0");
2255 m_regions
.Append((wxObject
*)newRegion
);
2256 if (m_text
.Number() > 0)
2258 newRegion
->ClearText();
2259 wxNode
*node
= m_text
.First();
2262 wxShapeTextLine
*textLine
= (wxShapeTextLine
*)node
->Data();
2263 wxNode
*next
= node
->Next();
2264 newRegion
->GetFormattedText().Append((wxObject
*)textLine
);
2274 void wxShape::Copy(wxShape
& copy
)
2277 copy
.m_xpos
= m_xpos
;
2278 copy
.m_ypos
= m_ypos
;
2280 copy
.m_brush
= m_brush
;
2281 copy
.m_textColour
= m_textColour
;
2282 copy
.m_centreResize
= m_centreResize
;
2283 copy
.m_maintainAspectRatio
= m_maintainAspectRatio
;
2284 copy
.m_attachmentMode
= m_attachmentMode
;
2285 copy
.m_spaceAttachments
= m_spaceAttachments
;
2286 copy
.m_highlighted
= m_highlighted
;
2287 copy
.m_rotation
= m_rotation
;
2288 copy
.m_textColourName
= m_textColourName
;
2289 copy
.m_regionName
= m_regionName
;
2291 copy
.m_sensitivity
= m_sensitivity
;
2292 copy
.m_draggable
= m_draggable
;
2293 copy
.m_fixedWidth
= m_fixedWidth
;
2294 copy
.m_fixedHeight
= m_fixedHeight
;
2295 copy
.m_formatMode
= m_formatMode
;
2296 copy
.m_drawHandles
= m_drawHandles
;
2298 copy
.m_visible
= m_visible
;
2299 copy
.m_shadowMode
= m_shadowMode
;
2300 copy
.m_shadowOffsetX
= m_shadowOffsetX
;
2301 copy
.m_shadowOffsetY
= m_shadowOffsetY
;
2302 copy
.m_shadowBrush
= m_shadowBrush
;
2304 copy
.m_branchNeckLength
= m_branchNeckLength
;
2305 copy
.m_branchStemLength
= m_branchStemLength
;
2306 copy
.m_branchSpacing
= m_branchSpacing
;
2308 // Copy text regions
2309 copy
.ClearRegions();
2310 wxNode
*node
= m_regions
.First();
2313 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
2314 wxShapeRegion
*newRegion
= new wxShapeRegion(*region
);
2315 copy
.m_regions
.Append(newRegion
);
2316 node
= node
->Next();
2320 copy
.ClearAttachments();
2321 node
= m_attachmentPoints
.First();
2324 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
2325 wxAttachmentPoint
*newPoint
= new wxAttachmentPoint
;
2326 newPoint
->m_id
= point
->m_id
;
2327 newPoint
->m_x
= point
->m_x
;
2328 newPoint
->m_y
= point
->m_y
;
2329 copy
.m_attachmentPoints
.Append((wxObject
*)newPoint
);
2330 node
= node
->Next();
2334 copy
.m_lines
.Clear();
2335 node
= m_lines
.First();
2338 wxLineShape
* line
= (wxLineShape
*) node
->Data();
2339 copy
.m_lines
.Append(line
);
2340 node
= node
->Next();
2344 // Create and return a new, fully copied object.
2345 wxShape
*wxShape::CreateNewCopy(bool resetMapping
, bool recompute
)
2348 oglObjectCopyMapping
.Clear();
2350 wxShape
* newObject
= (wxShape
*) GetClassInfo()->CreateObject();
2352 wxASSERT( (newObject
!= NULL
) );
2353 wxASSERT( (newObject
->IsKindOf(CLASSINFO(wxShape
))) );
2357 if (GetEventHandler() != this)
2359 wxShapeEvtHandler
* newHandler
= GetEventHandler()->CreateNewCopy();
2360 newObject
->SetEventHandler(newHandler
);
2361 newObject
->SetPreviousHandler(NULL
);
2362 newHandler
->SetPreviousHandler(newObject
);
2363 newHandler
->SetShape(newObject
);
2367 newObject
->Recompute();
2371 // Does the copying for this object, including copying event
2372 // handler data if any. Calls the virtual Copy function.
2373 void wxShape::CopyWithHandler(wxShape
& copy
)
2377 if (GetEventHandler() != this)
2379 wxASSERT( copy
.GetEventHandler() != NULL
);
2380 wxASSERT( copy
.GetEventHandler() != (©
) );
2381 wxASSERT( GetEventHandler()->GetClassInfo() == copy
.GetEventHandler()->GetClassInfo() );
2382 GetEventHandler()->CopyData(* (copy
.GetEventHandler()));
2387 // Default - make 6 control points
2388 void wxShape::MakeControlPoints()
2390 double maxX
, maxY
, minX
, minY
;
2392 GetBoundingBoxMax(&maxX
, &maxY
);
2393 GetBoundingBoxMin(&minX
, &minY
);
2395 double widthMin
= (double)(minX
+ CONTROL_POINT_SIZE
+ 2);
2396 double heightMin
= (double)(minY
+ CONTROL_POINT_SIZE
+ 2);
2398 // Offsets from main object
2399 double top
= (double)(- (heightMin
/ 2.0));
2400 double bottom
= (double)(heightMin
/ 2.0 + (maxY
- minY
));
2401 double left
= (double)(- (widthMin
/ 2.0));
2402 double right
= (double)(widthMin
/ 2.0 + (maxX
- minX
));
2404 wxControlPoint
*control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, left
, top
,
2405 CONTROL_POINT_DIAGONAL
);
2406 m_canvas
->AddShape(control
);
2407 m_controlPoints
.Append(control
);
2409 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, 0, top
,
2410 CONTROL_POINT_VERTICAL
);
2411 m_canvas
->AddShape(control
);
2412 m_controlPoints
.Append(control
);
2414 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, right
, top
,
2415 CONTROL_POINT_DIAGONAL
);
2416 m_canvas
->AddShape(control
);
2417 m_controlPoints
.Append(control
);
2419 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, right
, 0,
2420 CONTROL_POINT_HORIZONTAL
);
2421 m_canvas
->AddShape(control
);
2422 m_controlPoints
.Append(control
);
2424 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, right
, bottom
,
2425 CONTROL_POINT_DIAGONAL
);
2426 m_canvas
->AddShape(control
);
2427 m_controlPoints
.Append(control
);
2429 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, 0, bottom
,
2430 CONTROL_POINT_VERTICAL
);
2431 m_canvas
->AddShape(control
);
2432 m_controlPoints
.Append(control
);
2434 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, left
, bottom
,
2435 CONTROL_POINT_DIAGONAL
);
2436 m_canvas
->AddShape(control
);
2437 m_controlPoints
.Append(control
);
2439 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, left
, 0,
2440 CONTROL_POINT_HORIZONTAL
);
2441 m_canvas
->AddShape(control
);
2442 m_controlPoints
.Append(control
);
2446 void wxShape::MakeMandatoryControlPoints()
2448 wxNode
*node
= m_children
.First();
2451 wxShape
*child
= (wxShape
*)node
->Data();
2452 child
->MakeMandatoryControlPoints();
2453 node
= node
->Next();
2457 void wxShape::ResetMandatoryControlPoints()
2459 wxNode
*node
= m_children
.First();
2462 wxShape
*child
= (wxShape
*)node
->Data();
2463 child
->ResetMandatoryControlPoints();
2464 node
= node
->Next();
2468 void wxShape::ResetControlPoints()
2470 ResetMandatoryControlPoints();
2472 if (m_controlPoints
.Number() < 1)
2475 double maxX
, maxY
, minX
, minY
;
2477 GetBoundingBoxMax(&maxX
, &maxY
);
2478 GetBoundingBoxMin(&minX
, &minY
);
2480 double widthMin
= (double)(minX
+ CONTROL_POINT_SIZE
+ 2);
2481 double heightMin
= (double)(minY
+ CONTROL_POINT_SIZE
+ 2);
2483 // Offsets from main object
2484 double top
= (double)(- (heightMin
/ 2.0));
2485 double bottom
= (double)(heightMin
/ 2.0 + (maxY
- minY
));
2486 double left
= (double)(- (widthMin
/ 2.0));
2487 double right
= (double)(widthMin
/ 2.0 + (maxX
- minX
));
2489 wxNode
*node
= m_controlPoints
.First();
2490 wxControlPoint
*control
= (wxControlPoint
*)node
->Data();
2491 control
->m_xoffset
= left
; control
->m_yoffset
= top
;
2493 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2494 control
->m_xoffset
= 0; control
->m_yoffset
= top
;
2496 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2497 control
->m_xoffset
= right
; control
->m_yoffset
= top
;
2499 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2500 control
->m_xoffset
= right
; control
->m_yoffset
= 0;
2502 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2503 control
->m_xoffset
= right
; control
->m_yoffset
= bottom
;
2505 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2506 control
->m_xoffset
= 0; control
->m_yoffset
= bottom
;
2508 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2509 control
->m_xoffset
= left
; control
->m_yoffset
= bottom
;
2511 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2512 control
->m_xoffset
= left
; control
->m_yoffset
= 0;
2515 void wxShape::DeleteControlPoints(wxDC
*dc
)
2517 wxNode
*node
= m_controlPoints
.First();
2520 wxControlPoint
*control
= (wxControlPoint
*)node
->Data();
2522 control
->GetEventHandler()->OnErase(*dc
);
2523 m_canvas
->RemoveShape(control
);
2526 node
= m_controlPoints
.First();
2528 // Children of divisions are contained objects,
2530 if (!IsKindOf(CLASSINFO(wxDivisionShape
)))
2532 node
= m_children
.First();
2535 wxShape
*child
= (wxShape
*)node
->Data();
2536 child
->DeleteControlPoints(dc
);
2537 node
= node
->Next();
2542 void wxShape::OnDrawControlPoints(wxDC
& dc
)
2547 dc
.SetBrush(* wxBLACK_BRUSH
);
2548 dc
.SetPen(* wxBLACK_PEN
);
2550 wxNode
*node
= m_controlPoints
.First();
2553 wxControlPoint
*control
= (wxControlPoint
*)node
->Data();
2555 node
= node
->Next();
2557 // Children of divisions are contained objects,
2559 // This test bypasses the type facility for speed
2560 // (critical when drawing)
2561 if (!IsKindOf(CLASSINFO(wxDivisionShape
)))
2563 node
= m_children
.First();
2566 wxShape
*child
= (wxShape
*)node
->Data();
2567 child
->GetEventHandler()->OnDrawControlPoints(dc
);
2568 node
= node
->Next();
2573 void wxShape::OnEraseControlPoints(wxDC
& dc
)
2575 wxNode
*node
= m_controlPoints
.First();
2578 wxControlPoint
*control
= (wxControlPoint
*)node
->Data();
2580 node
= node
->Next();
2582 if (!IsKindOf(CLASSINFO(wxDivisionShape
)))
2584 node
= m_children
.First();
2587 wxShape
*child
= (wxShape
*)node
->Data();
2588 child
->GetEventHandler()->OnEraseControlPoints(dc
);
2589 node
= node
->Next();
2594 void wxShape::Select(bool select
, wxDC
* dc
)
2596 m_selected
= select
;
2599 MakeControlPoints();
2600 // Children of divisions are contained objects,
2602 if (!IsKindOf(CLASSINFO(wxDivisionShape
)))
2604 wxNode
*node
= m_children
.First();
2607 wxShape
*child
= (wxShape
*)node
->Data();
2608 child
->MakeMandatoryControlPoints();
2609 node
= node
->Next();
2613 GetEventHandler()->OnDrawControlPoints(*dc
);
2617 DeleteControlPoints(dc
);
2618 if (!IsKindOf(CLASSINFO(wxDivisionShape
)))
2620 wxNode
*node
= m_children
.First();
2623 wxShape
*child
= (wxShape
*)node
->Data();
2624 child
->DeleteControlPoints(dc
);
2625 node
= node
->Next();
2631 bool wxShape::Selected() const
2636 bool wxShape::AncestorSelected() const
2638 if (m_selected
) return TRUE
;
2642 return GetParent()->AncestorSelected();
2645 int wxShape::GetNumberOfAttachments() const
2647 // Should return the MAXIMUM attachment point id here,
2648 // so higher-level functions can iterate through all attachments,
2649 // even if they're not contiguous.
2650 if (m_attachmentPoints
.Number() == 0)
2655 wxNode
*node
= m_attachmentPoints
.First();
2658 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
2659 if (point
->m_id
> maxN
)
2661 node
= node
->Next();
2667 bool wxShape::AttachmentIsValid(int attachment
) const
2669 if (m_attachmentPoints
.Number() == 0)
2671 return ((attachment
>= 0) && (attachment
< 4)) ;
2674 wxNode
*node
= m_attachmentPoints
.First();
2677 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
2678 if (point
->m_id
== attachment
)
2680 node
= node
->Next();
2685 bool wxShape::GetAttachmentPosition(int attachment
, double *x
, double *y
,
2686 int nth
, int no_arcs
, wxLineShape
*line
)
2688 if (m_attachmentMode
== ATTACHMENT_MODE_NONE
)
2690 *x
= m_xpos
; *y
= m_ypos
;
2693 else if (m_attachmentMode
== ATTACHMENT_MODE_BRANCHING
)
2695 wxRealPoint pt
, stemPt
;
2696 GetBranchingAttachmentPoint(attachment
, nth
, pt
, stemPt
);
2701 else if (m_attachmentMode
== ATTACHMENT_MODE_EDGE
)
2703 if (m_attachmentPoints
.Number() > 0)
2705 wxNode
*node
= m_attachmentPoints
.First();
2708 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
2709 if (point
->m_id
== attachment
)
2711 *x
= (double)(m_xpos
+ point
->m_x
);
2712 *y
= (double)(m_ypos
+ point
->m_y
);
2715 node
= node
->Next();
2717 *x
= m_xpos
; *y
= m_ypos
;
2722 // Assume is rectangular
2724 GetBoundingBoxMax(&w
, &h
);
2725 double top
= (double)(m_ypos
+ h
/2.0);
2726 double bottom
= (double)(m_ypos
- h
/2.0);
2727 double left
= (double)(m_xpos
- w
/2.0);
2728 double right
= (double)(m_xpos
+ w
/2.0);
2730 bool isEnd
= (line
&& line
->IsEnd(this));
2732 int physicalAttachment
= LogicalToPhysicalAttachment(attachment
);
2735 switch (physicalAttachment
)
2739 wxRealPoint pt
= CalcSimpleAttachment(wxRealPoint(left
, bottom
), wxRealPoint(right
, bottom
),
2740 nth
, no_arcs
, line
);
2742 *x
= pt
.x
; *y
= pt
.y
;
2747 wxRealPoint pt
= CalcSimpleAttachment(wxRealPoint(right
, bottom
), wxRealPoint(right
, top
),
2748 nth
, no_arcs
, line
);
2750 *x
= pt
.x
; *y
= pt
.y
;
2755 wxRealPoint pt
= CalcSimpleAttachment(wxRealPoint(left
, top
), wxRealPoint(right
, top
),
2756 nth
, no_arcs
, line
);
2758 *x
= pt
.x
; *y
= pt
.y
;
2763 wxRealPoint pt
= CalcSimpleAttachment(wxRealPoint(left
, bottom
), wxRealPoint(left
, top
),
2764 nth
, no_arcs
, line
);
2766 *x
= pt
.x
; *y
= pt
.y
;
2781 void wxShape::GetBoundingBoxMax(double *w
, double *h
)
2784 GetBoundingBoxMin(&ww
, &hh
);
2785 if (m_shadowMode
!= SHADOW_NONE
)
2787 ww
+= m_shadowOffsetX
;
2788 hh
+= m_shadowOffsetY
;
2794 // Returns TRUE if image is a descendant of this composite
2795 bool wxShape::HasDescendant(wxShape
*image
)
2799 wxNode
*node
= m_children
.First();
2802 wxShape
*child
= (wxShape
*)node
->Data();
2803 bool ans
= child
->HasDescendant(image
);
2806 node
= node
->Next();
2811 // Clears points from a list of wxRealPoints, and clears list
2812 void wxShape::ClearPointList(wxList
& list
)
2814 wxNode
* node
= list
.First();
2817 wxRealPoint
* pt
= (wxRealPoint
*) node
->Data();
2820 node
= node
->Next();
2825 // Assuming the attachment lies along a vertical or horizontal line,
2826 // calculate the position on that point.
2827 wxRealPoint
wxShape::CalcSimpleAttachment(const wxRealPoint
& pt1
, const wxRealPoint
& pt2
,
2828 int nth
, int noArcs
, wxLineShape
* line
)
2830 bool isEnd
= (line
&& line
->IsEnd(this));
2832 // Are we horizontal or vertical?
2833 bool isHorizontal
= (oglRoughlyEqual(pt1
.y
, pt2
.y
) == TRUE
);
2839 wxRealPoint firstPoint
, secondPoint
;
2851 if (m_spaceAttachments
)
2853 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
2855 // Align line according to the next handle along
2856 wxRealPoint
*point
= line
->GetNextControlPoint(this);
2857 if (point
->x
< firstPoint
.x
)
2859 else if (point
->x
> secondPoint
.x
)
2865 x
= firstPoint
.x
+ (nth
+ 1)*(secondPoint
.x
- firstPoint
.x
)/(noArcs
+ 1);
2867 else x
= (secondPoint
.x
- firstPoint
.x
)/2.0; // Midpoint
2873 wxASSERT( oglRoughlyEqual(pt1
.x
, pt2
.x
) == TRUE
);
2875 wxRealPoint firstPoint
, secondPoint
;
2887 if (m_spaceAttachments
)
2889 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
2891 // Align line according to the next handle along
2892 wxRealPoint
*point
= line
->GetNextControlPoint(this);
2893 if (point
->y
< firstPoint
.y
)
2895 else if (point
->y
> secondPoint
.y
)
2901 y
= firstPoint
.y
+ (nth
+ 1)*(secondPoint
.y
- firstPoint
.y
)/(noArcs
+ 1);
2903 else y
= (secondPoint
.y
- firstPoint
.y
)/2.0; // Midpoint
2908 return wxRealPoint(x
, y
);
2911 // Return the zero-based position in m_lines of line.
2912 int wxShape::GetLinePosition(wxLineShape
* line
)
2915 for (i
= 0; i
< m_lines
.Number(); i
++)
2916 if ((wxLineShape
*) (m_lines
.Nth(i
)->Data()) == line
)
2926 // shoulder1 ->---------<- shoulder2
2928 // <- branching attachment point N-1
2930 // This function gets information about where branching connections go.
2931 // Returns FALSE if there are no lines at this attachment.
2932 bool wxShape::GetBranchingAttachmentInfo(int attachment
, wxRealPoint
& root
, wxRealPoint
& neck
,
2933 wxRealPoint
& shoulder1
, wxRealPoint
& shoulder2
)
2935 int physicalAttachment
= LogicalToPhysicalAttachment(attachment
);
2937 // Number of lines at this attachment.
2938 int lineCount
= GetAttachmentLineCount(attachment
);
2943 int totalBranchLength
= m_branchSpacing
* (lineCount
- 1);
2945 root
= GetBranchingAttachmentRoot(attachment
);
2947 // Assume that we have attachment points 0 to 3: top, right, bottom, left.
2948 switch (physicalAttachment
)
2953 neck
.y
= root
.y
- m_branchNeckLength
;
2955 shoulder1
.x
= root
.x
- (totalBranchLength
/2.0) ;
2956 shoulder2
.x
= root
.x
+ (totalBranchLength
/2.0) ;
2958 shoulder1
.y
= neck
.y
;
2959 shoulder2
.y
= neck
.y
;
2964 neck
.x
= root
.x
+ m_branchNeckLength
;
2967 shoulder1
.x
= neck
.x
;
2968 shoulder2
.x
= neck
.x
;
2970 shoulder1
.y
= neck
.y
- (totalBranchLength
/2.0) ;
2971 shoulder2
.y
= neck
.y
+ (totalBranchLength
/2.0) ;
2977 neck
.y
= root
.y
+ m_branchNeckLength
;
2979 shoulder1
.x
= root
.x
- (totalBranchLength
/2.0) ;
2980 shoulder2
.x
= root
.x
+ (totalBranchLength
/2.0) ;
2982 shoulder1
.y
= neck
.y
;
2983 shoulder2
.y
= neck
.y
;
2988 neck
.x
= root
.x
- m_branchNeckLength
;
2991 shoulder1
.x
= neck
.x
;
2992 shoulder2
.x
= neck
.x
;
2994 shoulder1
.y
= neck
.y
- (totalBranchLength
/2.0) ;
2995 shoulder2
.y
= neck
.y
+ (totalBranchLength
/2.0) ;
3000 wxFAIL_MSG( "Unrecognised attachment point in GetBranchingAttachmentInfo." );
3007 // n is the number of the adjoining line, from 0 to N-1 where N is the number of lines
3008 // at this attachment point.
3009 // Get the attachment point where the arc joins the stem, and also the point where the
3010 // the stem meets the shoulder.
3011 bool wxShape::GetBranchingAttachmentPoint(int attachment
, int n
, wxRealPoint
& pt
, wxRealPoint
& stemPt
)
3013 int physicalAttachment
= LogicalToPhysicalAttachment(attachment
);
3015 wxRealPoint root
, neck
, shoulder1
, shoulder2
;
3016 GetBranchingAttachmentInfo(attachment
, root
, neck
, shoulder1
, shoulder2
);
3018 // Assume that we have attachment points 0 to 3: top, right, bottom, left.
3019 switch (physicalAttachment
)
3023 pt
.y
= neck
.y
- m_branchStemLength
;
3024 pt
.x
= shoulder1
.x
+ n
*m_branchSpacing
;
3032 pt
.y
= neck
.y
+ m_branchStemLength
;
3033 pt
.x
= shoulder1
.x
+ n
*m_branchSpacing
;
3041 pt
.x
= neck
.x
+ m_branchStemLength
;
3042 pt
.y
= shoulder1
.y
+ n
*m_branchSpacing
;
3050 pt
.x
= neck
.x
- m_branchStemLength
;
3051 pt
.y
= shoulder1
.y
+ n
*m_branchSpacing
;
3059 wxFAIL_MSG( "Unrecognised attachment point in GetBranchingAttachmentPoint." );
3067 // Get the number of lines at this attachment position.
3068 int wxShape::GetAttachmentLineCount(int attachment
) const
3071 wxNode
* node
= m_lines
.First();
3074 wxLineShape
* lineShape
= (wxLineShape
*) node
->Data();
3075 if ((lineShape
->GetFrom() == this) && (lineShape
->GetAttachmentFrom() == attachment
))
3077 else if ((lineShape
->GetTo() == this) && (lineShape
->GetAttachmentTo() == attachment
))
3080 node
= node
->Next();
3085 // This function gets the root point at the given attachment.
3086 wxRealPoint
wxShape::GetBranchingAttachmentRoot(int attachment
)
3088 int physicalAttachment
= LogicalToPhysicalAttachment(attachment
);
3092 double width
, height
;
3093 GetBoundingBoxMax(& width
, & height
);
3095 // Assume that we have attachment points 0 to 3: top, right, bottom, left.
3096 switch (physicalAttachment
)
3101 root
.y
= GetY() - height
/2.0;
3106 root
.x
= GetX() + width
/2.0;
3113 root
.y
= GetY() + height
/2.0;
3118 root
.x
= GetX() - width
/2.0;
3124 wxFAIL_MSG( "Unrecognised attachment point in GetBranchingAttachmentRoot." );
3131 // Draw or erase the branches (not the actual arcs though)
3132 void wxShape::OnDrawBranches(wxDC
& dc
, int attachment
, bool erase
)
3134 int count
= GetAttachmentLineCount(attachment
);
3138 wxRealPoint root
, neck
, shoulder1
, shoulder2
;
3139 GetBranchingAttachmentInfo(attachment
, root
, neck
, shoulder1
, shoulder2
);
3143 dc
.SetPen(*wxWHITE_PEN
);
3144 dc
.SetBrush(*wxWHITE_BRUSH
);
3148 dc
.SetPen(*wxBLACK_PEN
);
3149 dc
.SetBrush(*wxBLACK_BRUSH
);
3153 dc
.DrawLine((long) root
.x
, (long) root
.y
, (long) neck
.x
, (long) neck
.y
);
3157 // Draw shoulder-to-shoulder line
3158 dc
.DrawLine((long) shoulder1
.x
, (long) shoulder1
.y
, (long) shoulder2
.x
, (long) shoulder2
.y
);
3160 // Draw all the little branches
3162 for (i
= 0; i
< count
; i
++)
3164 wxRealPoint pt
, stemPt
;
3165 GetBranchingAttachmentPoint(attachment
, i
, pt
, stemPt
);
3166 dc
.DrawLine((long) stemPt
.x
, (long) stemPt
.y
, (long) pt
.x
, (long) pt
.y
);
3168 if ((GetBranchStyle() & BRANCHING_ATTACHMENT_BLOB
) && (count
> 1))
3171 // dc.DrawEllipse((long) (stemPt.x + 0.5 - (blobSize/2.0)), (long) (stemPt.y + 0.5 - (blobSize/2.0)), blobSize, blobSize);
3172 dc
.DrawEllipse((long) (stemPt
.x
- (blobSize
/2.0)), (long) (stemPt
.y
- (blobSize
/2.0)), blobSize
, blobSize
);
3177 // Draw or erase the branches (not the actual arcs though)
3178 void wxShape::OnDrawBranches(wxDC
& dc
, bool erase
)
3180 if (m_attachmentMode
!= ATTACHMENT_MODE_BRANCHING
)
3183 int count
= GetNumberOfAttachments();
3185 for (i
= 0; i
< count
; i
++)
3186 OnDrawBranches(dc
, i
, erase
);
3189 // Only get the attachment position at the _edge_ of the shape, ignoring
3190 // branching mode. This is used e.g. to indicate the edge of interest, not the point
3191 // on the attachment branch.
3192 bool wxShape::GetAttachmentPositionEdge(int attachment
, double *x
, double *y
,
3193 int nth
, int no_arcs
, wxLineShape
*line
)
3195 int oldMode
= m_attachmentMode
;
3197 // Calculate as if to edge, not branch
3198 if (m_attachmentMode
== ATTACHMENT_MODE_BRANCHING
)
3199 m_attachmentMode
= ATTACHMENT_MODE_EDGE
;
3200 bool success
= GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
3201 m_attachmentMode
= oldMode
;
3206 // Rotate the standard attachment point from physical (0 is always North)
3207 // to logical (0 -> 1 if rotated by 90 degrees)
3208 int wxShape::PhysicalToLogicalAttachment(int physicalAttachment
) const
3210 const double pi
= 3.1415926535897932384626433832795 ;
3212 if (oglRoughlyEqual(GetRotation(), 0.0))
3214 i
= physicalAttachment
;
3216 else if (oglRoughlyEqual(GetRotation(), (pi
/2.0)))
3218 i
= physicalAttachment
- 1;
3220 else if (oglRoughlyEqual(GetRotation(), pi
))
3222 i
= physicalAttachment
- 2;
3224 else if (oglRoughlyEqual(GetRotation(), (3.0*pi
/2.0)))
3226 i
= physicalAttachment
- 3;
3229 // Can't handle -- assume the same.
3230 return physicalAttachment
;
3238 // Rotate the standard attachment point from logical
3239 // to physical (0 is always North)
3240 int wxShape::LogicalToPhysicalAttachment(int logicalAttachment
) const
3242 const double pi
= 3.1415926535897932384626433832795 ;
3244 if (oglRoughlyEqual(GetRotation(), 0.0))
3246 i
= logicalAttachment
;
3248 else if (oglRoughlyEqual(GetRotation(), (pi
/2.0)))
3250 i
= logicalAttachment
+ 1;
3252 else if (oglRoughlyEqual(GetRotation(), pi
))
3254 i
= logicalAttachment
+ 2;
3256 else if (oglRoughlyEqual(GetRotation(), (3.0*pi
/2.0)))
3258 i
= logicalAttachment
+ 3;
3261 // Can't handle -- assume the same.
3262 return logicalAttachment
;
3270 void wxShape::Rotate(double WXUNUSED(x
), double WXUNUSED(y
), double theta
)
3272 const double pi
= 3.1415926535897932384626433832795 ;
3274 if (m_rotation
< 0.0)
3278 else if (m_rotation
> 2*pi
)