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";
292 m_attachmentMode
= ATTACHMENT_MODE_NONE
;
293 m_spaceAttachments
= TRUE
;
294 m_disableLabel
= FALSE
;
295 m_fixedWidth
= FALSE
;
296 m_fixedHeight
= FALSE
;
297 m_drawHandles
= TRUE
;
298 m_sensitivity
= OP_ALL
;
301 m_formatMode
= FORMAT_CENTRE_HORIZ
| FORMAT_CENTRE_VERT
;
302 m_shadowMode
= SHADOW_NONE
;
305 m_shadowBrush
= wxBLACK_BRUSH
;
309 m_centreResize
= TRUE
;
310 m_maintainAspectRatio
= FALSE
;
311 m_highlighted
= FALSE
;
313 m_branchNeckLength
= 10;
314 m_branchStemLength
= 10;
315 m_branchSpacing
= 10;
316 m_branchStyle
= BRANCHING_ATTACHMENT_NORMAL
;
318 // Set up a default region. Much of the above will be put into
319 // the region eventually (the duplication is for compatibility)
320 wxShapeRegion
*region
= new wxShapeRegion
;
321 m_regions
.Append(region
);
322 region
->SetName("0");
323 region
->SetFont(g_oglNormalFont
);
324 region
->SetFormatMode(FORMAT_CENTRE_HORIZ
| FORMAT_CENTRE_VERT
);
325 region
->SetColour("BLACK");
331 m_parent
->GetChildren().DeleteObject(this);
338 m_canvas
->RemoveShape(this);
340 GetEventHandler()->OnDelete();
343 void wxShape::SetHighlight(bool hi
, bool recurse
)
348 wxNode
*node
= m_children
.First();
351 wxShape
*child
= (wxShape
*)node
->Data();
352 child
->SetHighlight(hi
, recurse
);
358 void wxShape::SetSensitivityFilter(int sens
, bool recursive
)
360 if (sens
& OP_DRAG_LEFT
)
365 m_sensitivity
= sens
;
368 wxNode
*node
= m_children
.First();
371 wxShape
*obj
= (wxShape
*)node
->Data();
372 obj
->SetSensitivityFilter(sens
, TRUE
);
378 void wxShape::SetDraggable(bool drag
, bool recursive
)
382 m_sensitivity
|= OP_DRAG_LEFT
;
384 if (m_sensitivity
& OP_DRAG_LEFT
)
385 m_sensitivity
= m_sensitivity
- OP_DRAG_LEFT
;
389 wxNode
*node
= m_children
.First();
392 wxShape
*obj
= (wxShape
*)node
->Data();
393 obj
->SetDraggable(drag
, TRUE
);
399 void wxShape::SetDrawHandles(bool drawH
)
401 m_drawHandles
= drawH
;
402 wxNode
*node
= m_children
.First();
405 wxShape
*obj
= (wxShape
*)node
->Data();
406 obj
->SetDrawHandles(drawH
);
411 void wxShape::SetShadowMode(int mode
, bool redraw
)
413 if (redraw
&& GetCanvas())
415 wxClientDC
dc(GetCanvas());
416 GetCanvas()->PrepareDC(dc
);
429 void wxShape::SetCanvas(wxShapeCanvas
*theCanvas
)
431 m_canvas
= theCanvas
;
432 wxNode
*node
= m_children
.First();
435 wxShape
*child
= (wxShape
*)node
->Data();
436 child
->SetCanvas(theCanvas
);
441 void wxShape::AddToCanvas(wxShapeCanvas
*theCanvas
, wxShape
*addAfter
)
443 theCanvas
->AddShape(this, addAfter
);
444 wxNode
*node
= m_children
.First();
445 wxShape
*lastImage
= this;
448 wxShape
*object
= (wxShape
*)node
->Data();
449 object
->AddToCanvas(theCanvas
, lastImage
);
456 // Insert at front of canvas
457 void wxShape::InsertInCanvas(wxShapeCanvas
*theCanvas
)
459 theCanvas
->InsertShape(this);
460 wxNode
*node
= m_children
.First();
461 wxShape
*lastImage
= this;
464 wxShape
*object
= (wxShape
*)node
->Data();
465 object
->AddToCanvas(theCanvas
, lastImage
);
472 void wxShape::RemoveFromCanvas(wxShapeCanvas
*theCanvas
)
476 theCanvas
->RemoveShape(this);
477 wxNode
*node
= m_children
.First();
480 wxShape
*object
= (wxShape
*)node
->Data();
481 object
->RemoveFromCanvas(theCanvas
);
487 void wxShape::ClearAttachments()
489 wxNode
*node
= m_attachmentPoints
.First();
492 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
496 m_attachmentPoints
.Clear();
499 void wxShape::ClearText(int regionId
)
503 m_text
.DeleteContents(TRUE
);
505 m_text
.DeleteContents(FALSE
);
507 wxNode
*node
= m_regions
.Nth(regionId
);
510 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
514 void wxShape::ClearRegions()
516 wxNode
*node
= m_regions
.First();
519 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
520 wxNode
*next
= node
->Next();
527 void wxShape::AddRegion(wxShapeRegion
*region
)
529 m_regions
.Append(region
);
532 void wxShape::SetDefaultRegionSize()
534 wxNode
*node
= m_regions
.First();
536 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
538 GetBoundingBoxMin(&w
, &h
);
539 region
->SetSize(w
, h
);
542 bool wxShape::HitTest(double x
, double y
, int *attachment
, double *distance
)
547 double width
= 0.0, height
= 0.0;
548 GetBoundingBoxMin(&width
, &height
);
549 if (fabs(width
) < 4.0) width
= 4.0;
550 if (fabs(height
) < 4.0) height
= 4.0;
552 width
+= (double)4.0; height
+= (double)4.0; // Allowance for inaccurate mousing
554 double left
= (double)(m_xpos
- (width
/2.0));
555 double top
= (double)(m_ypos
- (height
/2.0));
556 double right
= (double)(m_xpos
+ (width
/2.0));
557 double bottom
= (double)(m_ypos
+ (height
/2.0));
559 int nearest_attachment
= 0;
561 // If within the bounding box, check the attachment points
562 // within the object.
564 if (x
>= left
&& x
<= right
&& y
>= top
&& y
<= bottom
)
566 int n
= GetNumberOfAttachments();
567 double nearest
= 999999.0;
569 // GetAttachmentPosition[Edge] takes a logical attachment position,
570 // i.e. if it's rotated through 90%, position 0 is East-facing.
572 for (int i
= 0; i
< n
; i
++)
575 if (GetAttachmentPositionEdge(i
, &xp
, &yp
))
577 double l
= (double)sqrt(((xp
- x
) * (xp
- x
)) +
578 ((yp
- y
) * (yp
- y
)));
583 nearest_attachment
= i
;
587 *attachment
= nearest_attachment
;
594 // Format a text string according to the region size, adding
595 // strings with positions to region text list
597 static bool GraphicsInSizeToContents
= FALSE
; // Infinite recursion elimination
598 void wxShape::FormatText(wxDC
& dc
, const wxString
& s
, int i
)
603 if (m_regions
.Number() < 1)
605 wxNode
*node
= m_regions
.Nth(i
);
609 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
611 dc
.SetFont(* region
->GetFont());
613 region
->GetSize(&w
, &h
);
615 wxStringList
*stringList
= oglFormatText(dc
, s
, (w
-5), (h
-5), region
->GetFormatMode());
616 node
= stringList
->First();
619 char *s
= (char *)node
->Data();
620 wxShapeTextLine
*line
= new wxShapeTextLine(0.0, 0.0, s
);
621 region
->GetFormattedText().Append((wxObject
*)line
);
627 // Don't try to resize an object with more than one image (this case should be dealt
628 // with by overriden handlers)
629 if ((region
->GetFormatMode() & FORMAT_SIZE_TO_CONTENTS
) &&
630 (region
->GetFormattedText().Number() > 0) &&
631 (m_regions
.Number() == 1) && !GraphicsInSizeToContents
)
633 oglGetCentredTextExtent(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, w
, h
, &actualW
, &actualH
);
634 if ((actualW
+m_textMarginX
!= w
) || (actualH
+m_textMarginY
!= h
))
636 // If we are a descendant of a composite, must make sure the composite gets
638 wxShape
*topAncestor
= GetTopAncestor();
640 if (topAncestor
!= this)
642 // Make sure we don't recurse infinitely
643 GraphicsInSizeToContents
= TRUE
;
645 wxCompositeShape
*composite
= (wxCompositeShape
*)topAncestor
;
646 composite
->Erase(dc
);
647 SetSize(actualW
+m_textMarginX
, actualH
+m_textMarginY
);
648 Move(dc
, m_xpos
, m_ypos
);
649 composite
->CalculateSize();
650 if (composite
->Selected())
652 composite
->DeleteControlPoints(& dc
);
653 composite
->MakeControlPoints();
654 composite
->MakeMandatoryControlPoints();
656 // Where infinite recursion might happen if we didn't stop it
659 GraphicsInSizeToContents
= FALSE
;
664 SetSize(actualW
+m_textMarginX
, actualH
+m_textMarginY
);
665 Move(dc
, m_xpos
, m_ypos
);
667 SetSize(actualW
+m_textMarginX
, actualH
+m_textMarginY
);
668 Move(dc
, m_xpos
, m_ypos
);
672 oglCentreText(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, actualW
, actualH
, region
->GetFormatMode());
676 void wxShape::Recentre(wxDC
& dc
)
679 GetBoundingBoxMin(&w
, &h
);
681 int noRegions
= m_regions
.Number();
682 for (int i
= 0; i
< noRegions
; i
++)
684 wxNode
*node
= m_regions
.Nth(i
);
687 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
688 oglCentreText(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, w
, h
, region
->GetFormatMode());
693 bool wxShape::GetPerimeterPoint(double x1
, double y1
,
694 double x2
, double y2
,
695 double *x3
, double *y3
)
700 void wxShape::SetPen(wxPen
*the_pen
)
705 void wxShape::SetBrush(wxBrush
*the_brush
)
710 // Get the top-most (non-division) ancestor, or self
711 wxShape
*wxShape::GetTopAncestor()
716 if (GetParent()->IsKindOf(CLASSINFO(wxDivisionShape
)))
718 else return GetParent()->GetTopAncestor();
725 void wxShape::SetFont(wxFont
*the_font
, int regionId
)
728 wxNode
*node
= m_regions
.Nth(regionId
);
731 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
732 region
->SetFont(the_font
);
735 wxFont
*wxShape::GetFont(int n
) const
737 wxNode
*node
= m_regions
.Nth(n
);
740 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
741 return region
->GetFont();
744 void wxShape::SetFormatMode(int mode
, int regionId
)
746 wxNode
*node
= m_regions
.Nth(regionId
);
749 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
750 region
->SetFormatMode(mode
);
753 int wxShape::GetFormatMode(int regionId
) const
755 wxNode
*node
= m_regions
.Nth(regionId
);
758 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
759 return region
->GetFormatMode();
762 void wxShape::SetTextColour(const wxString
& the_colour
, int regionId
)
764 wxColour
*wxcolour
= wxTheColourDatabase
->FindColour(the_colour
);
765 m_textColour
= wxcolour
;
766 m_textColourName
= the_colour
;
768 wxNode
*node
= m_regions
.Nth(regionId
);
771 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
772 region
->SetColour(the_colour
);
775 wxString
wxShape::GetTextColour(int regionId
) const
777 wxNode
*node
= m_regions
.Nth(regionId
);
780 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
781 return region
->GetColour();
784 void wxShape::SetRegionName(const wxString
& name
, int regionId
)
786 wxNode
*node
= m_regions
.Nth(regionId
);
789 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
790 region
->SetName(name
);
793 wxString
wxShape::GetRegionName(int regionId
)
795 wxNode
*node
= m_regions
.Nth(regionId
);
798 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
799 return region
->GetName();
802 int wxShape::GetRegionId(const wxString
& name
)
804 wxNode
*node
= m_regions
.First();
808 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
809 if (region
->GetName() == name
)
817 // Name all m_regions in all subimages recursively.
818 void wxShape::NameRegions(const wxString
& parentName
)
820 int n
= GetNumberOfTextRegions();
822 for (int i
= 0; i
< n
; i
++)
824 if (parentName
.Length() > 0)
825 sprintf(buf
, "%s.%d", (const char*) parentName
, i
);
827 sprintf(buf
, "%d", i
);
828 SetRegionName(buf
, i
);
830 wxNode
*node
= m_children
.First();
834 wxShape
*child
= (wxShape
*)node
->Data();
835 if (parentName
.Length() > 0)
836 sprintf(buf
, "%s.%d", (const char*) parentName
, j
);
838 sprintf(buf
, "%d", j
);
839 child
->NameRegions(buf
);
845 // Get a region by name, possibly looking recursively into composites.
846 wxShape
*wxShape::FindRegion(const wxString
& name
, int *regionId
)
848 int id
= GetRegionId(name
);
855 wxNode
*node
= m_children
.First();
858 wxShape
*child
= (wxShape
*)node
->Data();
859 wxShape
*actualImage
= child
->FindRegion(name
, regionId
);
867 // Finds all region names for this image (composite or simple).
868 // Supply empty string list.
869 void wxShape::FindRegionNames(wxStringList
& list
)
871 int n
= GetNumberOfTextRegions();
872 for (int i
= 0; i
< n
; i
++)
874 wxString
name(GetRegionName(i
));
875 list
.Add((const char*) name
);
878 wxNode
*node
= m_children
.First();
881 wxShape
*child
= (wxShape
*)node
->Data();
882 child
->FindRegionNames(list
);
887 void wxShape::AssignNewIds()
891 wxNode
*node
= m_children
.First();
894 wxShape
*child
= (wxShape
*)node
->Data();
895 child
->AssignNewIds();
900 void wxShape::OnDraw(wxDC
& dc
)
904 void wxShape::OnMoveLinks(wxDC
& dc
)
906 // Want to set the ends of all attached links
907 // to point to/from this object
909 wxNode
*current
= m_lines
.First();
912 wxLineShape
*line
= (wxLineShape
*)current
->Data();
913 line
->GetEventHandler()->OnMoveLink(dc
);
914 current
= current
->Next();
919 void wxShape::OnDrawContents(wxDC
& dc
)
921 double bound_x
, bound_y
;
922 GetBoundingBoxMin(&bound_x
, &bound_y
);
923 if (m_regions
.Number() < 1) return;
925 if (m_pen
) dc
.SetPen(* m_pen
);
927 wxShapeRegion
*region
= (wxShapeRegion
*)m_regions
.First()->Data();
928 if (region
->GetFont()) dc
.SetFont(* region
->GetFont());
930 dc
.SetTextForeground(* (region
->GetActualColourObject()));
931 dc
.SetBackgroundMode(wxTRANSPARENT
);
934 oglCentreText(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, bound_x
, bound_y
, region
->GetFormatMode());
937 if (!GetDisableLabel())
939 oglDrawFormattedText(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, bound_x
, bound_y
, region
->GetFormatMode());
943 void wxShape::DrawContents(wxDC
& dc
)
945 GetEventHandler()->OnDrawContents(dc
);
948 void wxShape::OnSize(double x
, double y
)
952 bool wxShape::OnMovePre(wxDC
& dc
, double x
, double y
, double old_x
, double old_y
, bool display
)
957 void wxShape::OnMovePost(wxDC
& dc
, double x
, double y
, double old_x
, double old_y
, bool display
)
961 void wxShape::OnErase(wxDC
& dc
)
967 wxNode
*current
= m_lines
.First();
970 wxLineShape
*line
= (wxLineShape
*)current
->Data();
971 line
->GetEventHandler()->OnErase(dc
);
972 current
= current
->Next();
974 GetEventHandler()->OnEraseContents(dc
);
977 void wxShape::OnEraseContents(wxDC
& dc
)
982 double maxX
, maxY
, minX
, minY
;
985 GetBoundingBoxMin(&minX
, &minY
);
986 GetBoundingBoxMax(&maxX
, &maxY
);
987 double topLeftX
= (double)(xp
- (maxX
/ 2.0) - 2.0);
988 double topLeftY
= (double)(yp
- (maxY
/ 2.0) - 2.0);
992 penWidth
= m_pen
->GetWidth();
994 dc
.SetPen(GetBackgroundPen());
995 dc
.SetBrush(GetBackgroundBrush());
997 dc
.DrawRectangle(WXROUND(topLeftX
- penWidth
), WXROUND(topLeftY
- penWidth
),
998 WXROUND(maxX
+ penWidth
*2.0 + 4.0), WXROUND(maxY
+ penWidth
*2.0 + 4.0));
1001 void wxShape::EraseLinks(wxDC
& dc
, int attachment
, bool recurse
)
1006 wxNode
*current
= m_lines
.First();
1009 wxLineShape
*line
= (wxLineShape
*)current
->Data();
1010 if (attachment
== -1 || ((line
->GetTo() == this && line
->GetAttachmentTo() == attachment
) ||
1011 (line
->GetFrom() == this && line
->GetAttachmentFrom() == attachment
)))
1012 line
->GetEventHandler()->OnErase(dc
);
1013 current
= current
->Next();
1017 wxNode
*node
= m_children
.First();
1020 wxShape
*child
= (wxShape
*)node
->Data();
1021 child
->EraseLinks(dc
, attachment
, recurse
);
1022 node
= node
->Next();
1027 void wxShape::DrawLinks(wxDC
& dc
, int attachment
, bool recurse
)
1032 wxNode
*current
= m_lines
.First();
1035 wxLineShape
*line
= (wxLineShape
*)current
->Data();
1036 if (attachment
== -1 ||
1037 (line
->GetTo() == this && line
->GetAttachmentTo() == attachment
) ||
1038 (line
->GetFrom() == this && line
->GetAttachmentFrom() == attachment
))
1040 current
= current
->Next();
1044 wxNode
*node
= m_children
.First();
1047 wxShape
*child
= (wxShape
*)node
->Data();
1048 child
->DrawLinks(dc
, attachment
, recurse
);
1049 node
= node
->Next();
1054 // Returns TRUE if pt1 <= pt2 in the sense that one point comes before another on an
1055 // edge of the shape.
1056 // attachmentPoint is the attachment point (= side) in question.
1058 // This is the default, rectangular implementation.
1059 bool wxShape::AttachmentSortTest(int attachmentPoint
, const wxRealPoint
& pt1
, const wxRealPoint
& pt2
)
1061 int physicalAttachment
= LogicalToPhysicalAttachment(attachmentPoint
);
1062 switch (physicalAttachment
)
1067 return (pt1
.x
<= pt2
.x
) ;
1073 return (pt1
.y
<= pt2
.y
) ;
1081 bool wxShape::MoveLineToNewAttachment(wxDC
& dc
, wxLineShape
*to_move
,
1084 if (GetAttachmentMode() == ATTACHMENT_MODE_NONE
)
1087 int newAttachment
, oldAttachment
;
1090 // Is (x, y) on this object? If so, find the new attachment point
1091 // the user has moved the point to
1092 bool hit
= HitTest(x
, y
, &newAttachment
, &distance
);
1098 if (to_move
->GetTo() == this)
1099 oldAttachment
= to_move
->GetAttachmentTo();
1101 oldAttachment
= to_move
->GetAttachmentFrom();
1103 // The links in a new ordering.
1106 // First, add all links to the new list.
1107 wxNode
*node
= m_lines
.First();
1110 newOrdering
.Append(node
->Data());
1111 node
= node
->Next();
1114 // Delete the line object from the list of links; we're going to move
1115 // it to another position in the list
1116 newOrdering
.DeleteObject(to_move
);
1118 double old_x
= (double) -99999.9;
1119 double old_y
= (double) -99999.9;
1121 node
= newOrdering
.First();
1124 while (!found
&& node
)
1126 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1127 if ((line
->GetTo() == this && oldAttachment
== line
->GetAttachmentTo()) ||
1128 (line
->GetFrom() == this && oldAttachment
== line
->GetAttachmentFrom()))
1130 double startX
, startY
, endX
, endY
;
1132 line
->GetEnds(&startX
, &startY
, &endX
, &endY
);
1133 if (line
->GetTo() == this)
1143 wxRealPoint
thisPoint(xp
, yp
);
1144 wxRealPoint
lastPoint(old_x
, old_y
);
1145 wxRealPoint
newPoint(x
, y
);
1147 if (AttachmentSortTest(newAttachment
, newPoint
, thisPoint
) && AttachmentSortTest(newAttachment
, lastPoint
, newPoint
))
1150 newOrdering
.Insert(node
, to_move
);
1156 node
= node
->Next();
1160 newOrdering
.Append(to_move
);
1162 GetEventHandler()->OnChangeAttachment(newAttachment
, to_move
, newOrdering
);
1167 void wxShape::OnChangeAttachment(int attachment
, wxLineShape
* line
, wxList
& ordering
)
1169 if (line
->GetTo() == this)
1170 line
->SetAttachmentTo(attachment
);
1172 line
->SetAttachmentFrom(attachment
);
1174 ApplyAttachmentOrdering(ordering
);
1176 wxClientDC
dc(GetCanvas());
1177 GetCanvas()->PrepareDC(dc
);
1181 if (!GetCanvas()->GetQuickEditMode()) GetCanvas()->Redraw(dc
);
1184 // Reorders the lines according to the given list.
1185 void wxShape::ApplyAttachmentOrdering(wxList
& linesToSort
)
1187 // This is a temporary store of all the lines.
1190 wxNode
*node
= m_lines
.First();
1193 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1194 linesStore
.Append(line
);
1195 node
= node
->Next();;
1200 node
= linesToSort
.First();
1203 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1204 if (linesStore
.Member(line
))
1207 linesStore
.DeleteObject(line
);
1208 m_lines
.Append(line
);
1210 node
= node
->Next();
1213 // Now add any lines that haven't been listed in linesToSort.
1214 node
= linesStore
.First();
1217 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1218 m_lines
.Append(line
);
1219 node
= node
->Next();
1223 // Reorders the lines coming into the node image at this attachment
1224 // position, in the order in which they appear in linesToSort.
1225 // Any remaining lines not in the list will be added to the end.
1226 void wxShape::SortLines(int attachment
, wxList
& linesToSort
)
1228 // This is a temporary store of all the lines at this attachment
1229 // point. We'll tick them off as we've processed them.
1230 wxList linesAtThisAttachment
;
1232 wxNode
*node
= m_lines
.First();
1235 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1236 wxNode
*next
= node
->Next();
1237 if ((line
->GetTo() == this && line
->GetAttachmentTo() == attachment
) ||
1238 (line
->GetFrom() == this && line
->GetAttachmentFrom() == attachment
))
1240 linesAtThisAttachment
.Append(line
);
1244 else node
= node
->Next();
1247 node
= linesToSort
.First();
1250 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1251 if (linesAtThisAttachment
.Member(line
))
1254 linesAtThisAttachment
.DeleteObject(line
);
1255 m_lines
.Append(line
);
1257 node
= node
->Next();
1260 // Now add any lines that haven't been listed in linesToSort.
1261 node
= linesAtThisAttachment
.First();
1264 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1265 m_lines
.Append(line
);
1266 node
= node
->Next();
1270 void wxShape::OnHighlight(wxDC
& dc
)
1274 void wxShape::OnLeftClick(double x
, double y
, int keys
, int attachment
)
1276 if ((m_sensitivity
& OP_CLICK_LEFT
) != OP_CLICK_LEFT
)
1282 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1283 m_parent
->GetEventHandler()->OnLeftClick(x
, y
, keys
, attachment
);
1289 void wxShape::OnRightClick(double x
, double y
, int keys
, int attachment
)
1291 if ((m_sensitivity
& OP_CLICK_RIGHT
) != OP_CLICK_RIGHT
)
1297 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1298 m_parent
->GetEventHandler()->OnRightClick(x
, y
, keys
, attachment
);
1304 double DragOffsetX
= 0.0;
1305 double DragOffsetY
= 0.0;
1307 void wxShape::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
1309 if ((m_sensitivity
& OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
1315 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1316 m_parent
->GetEventHandler()->OnDragLeft(draw
, x
, y
, keys
, attachment
);
1321 wxClientDC
dc(GetCanvas());
1322 GetCanvas()->PrepareDC(dc
);
1324 dc
.SetLogicalFunction(OGLRBLF
);
1326 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1327 dc
.SetPen(dottedPen
);
1328 dc
.SetBrush(* wxTRANSPARENT_BRUSH
);
1331 xx
= x
+ DragOffsetX
;
1332 yy
= y
+ DragOffsetY
;
1334 m_canvas
->Snap(&xx
, &yy
);
1335 // m_xpos = xx; m_ypos = yy;
1337 GetBoundingBoxMax(&w
, &h
);
1338 GetEventHandler()->OnDrawOutline(dc
, xx
, yy
, w
, h
);
1341 void wxShape::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
1343 if ((m_sensitivity
& OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
1349 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1350 m_parent
->GetEventHandler()->OnBeginDragLeft(x
, y
, keys
, attachment
);
1355 DragOffsetX
= m_xpos
- x
;
1356 DragOffsetY
= m_ypos
- y
;
1358 wxClientDC
dc(GetCanvas());
1359 GetCanvas()->PrepareDC(dc
);
1361 // New policy: don't erase shape until end of drag.
1365 xx
= x
+ DragOffsetX
;
1366 yy
= y
+ DragOffsetY
;
1367 m_canvas
->Snap(&xx
, &yy
);
1368 // m_xpos = xx; m_ypos = yy;
1369 dc
.SetLogicalFunction(OGLRBLF
);
1371 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1372 dc
.SetPen(dottedPen
);
1373 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1376 GetBoundingBoxMax(&w
, &h
);
1377 GetEventHandler()->OnDrawOutline(dc
, xx
, yy
, w
, h
);
1378 m_canvas
->CaptureMouse();
1381 void wxShape::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
1383 m_canvas
->ReleaseMouse();
1384 if ((m_sensitivity
& OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
1390 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1391 m_parent
->GetEventHandler()->OnEndDragLeft(x
, y
, keys
, attachment
);
1396 wxClientDC
dc(GetCanvas());
1397 GetCanvas()->PrepareDC(dc
);
1399 dc
.SetLogicalFunction(wxCOPY
);
1401 double xx
= x
+ DragOffsetX
;
1402 double yy
= y
+ DragOffsetY
;
1403 m_canvas
->Snap(&xx
, &yy
);
1404 // canvas->Snap(&m_xpos, &m_ypos);
1406 // New policy: erase shape at end of drag.
1410 if (m_canvas
&& !m_canvas
->GetQuickEditMode()) m_canvas
->Redraw(dc
);
1413 void wxShape::OnDragRight(bool draw
, double x
, double y
, int keys
, int attachment
)
1415 if ((m_sensitivity
& OP_DRAG_RIGHT
) != OP_DRAG_RIGHT
)
1421 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1422 m_parent
->GetEventHandler()->OnDragRight(draw
, x
, y
, keys
, attachment
);
1428 void wxShape::OnBeginDragRight(double x
, double y
, int keys
, int attachment
)
1430 if ((m_sensitivity
& OP_DRAG_RIGHT
) != OP_DRAG_RIGHT
)
1436 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1437 m_parent
->GetEventHandler()->OnBeginDragRight(x
, y
, keys
, attachment
);
1443 void wxShape::OnEndDragRight(double x
, double y
, int keys
, int attachment
)
1445 if ((m_sensitivity
& OP_DRAG_RIGHT
) != OP_DRAG_RIGHT
)
1451 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1452 m_parent
->GetEventHandler()->OnEndDragRight(x
, y
, keys
, attachment
);
1458 void wxShape::OnDrawOutline(wxDC
& dc
, double x
, double y
, double w
, double h
)
1460 double top_left_x
= (double)(x
- w
/2.0);
1461 double top_left_y
= (double)(y
- h
/2.0);
1462 double top_right_x
= (double)(top_left_x
+ w
);
1463 double top_right_y
= (double)top_left_y
;
1464 double bottom_left_x
= (double)top_left_x
;
1465 double bottom_left_y
= (double)(top_left_y
+ h
);
1466 double bottom_right_x
= (double)top_right_x
;
1467 double bottom_right_y
= (double)bottom_left_y
;
1470 points
[0].x
= WXROUND(top_left_x
); points
[0].y
= WXROUND(top_left_y
);
1471 points
[1].x
= WXROUND(top_right_x
); points
[1].y
= WXROUND(top_right_y
);
1472 points
[2].x
= WXROUND(bottom_right_x
); points
[2].y
= WXROUND(bottom_right_y
);
1473 points
[3].x
= WXROUND(bottom_left_x
); points
[3].y
= WXROUND(bottom_left_y
);
1474 points
[4].x
= WXROUND(top_left_x
); points
[4].y
= WXROUND(top_left_y
);
1476 dc
.DrawLines(5, points
);
1479 void wxShape::Attach(wxShapeCanvas
*can
)
1484 void wxShape::Detach()
1489 void wxShape::Move(wxDC
& dc
, double x
, double y
, bool display
)
1491 double old_x
= m_xpos
;
1492 double old_y
= m_ypos
;
1494 if (!GetEventHandler()->OnMovePre(dc
, x
, y
, old_x
, old_y
, display
))
1501 m_xpos
= x
; m_ypos
= y
;
1503 ResetControlPoints();
1510 GetEventHandler()->OnMovePost(dc
, x
, y
, old_x
, old_y
, display
);
1513 void wxShape::MoveLinks(wxDC
& dc
)
1515 GetEventHandler()->OnMoveLinks(dc
);
1519 void wxShape::Draw(wxDC
& dc
)
1523 GetEventHandler()->OnDraw(dc
);
1524 GetEventHandler()->OnDrawContents(dc
);
1525 GetEventHandler()->OnDrawControlPoints(dc
);
1526 GetEventHandler()->OnDrawBranches(dc
);
1530 void wxShape::Flash()
1534 wxClientDC
dc(GetCanvas());
1535 GetCanvas()->PrepareDC(dc
);
1537 dc
.SetLogicalFunction(OGLRBLF
);
1539 dc
.SetLogicalFunction(wxCOPY
);
1544 void wxShape::Show(bool show
)
1547 wxNode
*node
= m_children
.First();
1550 wxShape
*image
= (wxShape
*)node
->Data();
1552 node
= node
->Next();
1556 void wxShape::Erase(wxDC
& dc
)
1558 GetEventHandler()->OnErase(dc
);
1559 GetEventHandler()->OnEraseControlPoints(dc
);
1560 GetEventHandler()->OnDrawBranches(dc
, TRUE
);
1563 void wxShape::EraseContents(wxDC
& dc
)
1565 GetEventHandler()->OnEraseContents(dc
);
1568 void wxShape::AddText(const wxString
& string
)
1570 wxNode
*node
= m_regions
.First();
1573 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
1574 region
->ClearText();
1575 wxShapeTextLine
*new_line
=
1576 new wxShapeTextLine(0.0, 0.0, string
);
1577 region
->GetFormattedText().Append(new_line
);
1579 m_formatted
= FALSE
;
1582 void wxShape::SetSize(double x
, double y
, bool recursive
)
1584 SetAttachmentSize(x
, y
);
1585 SetDefaultRegionSize();
1588 void wxShape::SetAttachmentSize(double w
, double h
)
1592 double width
, height
;
1593 GetBoundingBoxMin(&width
, &height
);
1596 else scaleX
= w
/width
;
1599 else scaleY
= h
/height
;
1601 wxNode
*node
= m_attachmentPoints
.First();
1604 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
1605 point
->m_x
= (double)(point
->m_x
* scaleX
);
1606 point
->m_y
= (double)(point
->m_y
* scaleY
);
1607 node
= node
->Next();
1611 // Add line FROM this object
1612 void wxShape::AddLine(wxLineShape
*line
, wxShape
*other
,
1613 int attachFrom
, int attachTo
,
1614 // The line ordering
1615 int positionFrom
, int positionTo
)
1617 if (positionFrom
== -1)
1619 if (!m_lines
.Member(line
))
1620 m_lines
.Append(line
);
1624 // Don't preserve old ordering if we have new ordering instructions
1625 m_lines
.DeleteObject(line
);
1626 if (positionFrom
< m_lines
.Number())
1628 wxNode
* node
= m_lines
.Nth(positionFrom
);
1629 m_lines
.Insert(node
, line
);
1632 m_lines
.Append(line
);
1635 if (positionTo
== -1)
1637 if (!other
->m_lines
.Member(line
))
1638 other
->m_lines
.Append(line
);
1642 // Don't preserve old ordering if we have new ordering instructions
1643 other
->m_lines
.DeleteObject(line
);
1644 if (positionTo
< other
->m_lines
.Number())
1646 wxNode
* node
= other
->m_lines
.Nth(positionTo
);
1647 other
->m_lines
.Insert(node
, line
);
1650 other
->m_lines
.Append(line
);
1653 // Wrong: doesn't preserve ordering of shape already linked
1654 m_lines
.DeleteObject(line
);
1655 other
->m_lines
.DeleteObject(line
);
1657 if (positionFrom
== -1)
1658 m_lines
.Append(line
);
1661 if (positionFrom
< m_lines
.Number())
1663 wxNode
* node
= m_lines
.Nth(positionFrom
);
1664 m_lines
.Insert(node
, line
);
1667 m_lines
.Append(line
);
1670 if (positionTo
== -1)
1671 other
->m_lines
.Append(line
);
1674 if (positionTo
< other
->m_lines
.Number())
1676 wxNode
* node
= other
->m_lines
.Nth(positionTo
);
1677 other
->m_lines
.Insert(node
, line
);
1680 other
->m_lines
.Append(line
);
1684 line
->SetFrom(this);
1686 line
->SetAttachments(attachFrom
, attachTo
);
1689 void wxShape::RemoveLine(wxLineShape
*line
)
1691 if (line
->GetFrom() == this)
1692 line
->GetTo()->m_lines
.DeleteObject(line
);
1694 line
->GetFrom()->m_lines
.DeleteObject(line
);
1696 m_lines
.DeleteObject(line
);
1700 void wxShape::WriteAttributes(wxExpr
*clause
)
1702 clause
->AddAttributeValueString("type", GetClassInfo()->GetClassName());
1703 clause
->AddAttributeValue("id", m_id
);
1707 int penWidth
= m_pen
->GetWidth();
1708 int penStyle
= m_pen
->GetStyle();
1710 clause
->AddAttributeValue("pen_width", (long)penWidth
);
1711 if (penStyle
!= wxSOLID
)
1712 clause
->AddAttributeValue("pen_style", (long)penStyle
);
1714 wxString penColour
= wxTheColourDatabase
->FindName(m_pen
->GetColour());
1715 if (penColour
== "")
1717 wxString
hex(oglColourToHex(m_pen
->GetColour()));
1718 hex
= wxString("#") + hex
;
1719 clause
->AddAttributeValueString("pen_colour", hex
);
1721 else if (penColour
!= "BLACK")
1722 clause
->AddAttributeValueString("pen_colour", penColour
);
1727 wxString brushColour
= wxTheColourDatabase
->FindName(m_brush
->GetColour());
1729 if (brushColour
== "")
1731 wxString
hex(oglColourToHex(m_brush
->GetColour()));
1732 hex
= wxString("#") + hex
;
1733 clause
->AddAttributeValueString("brush_colour", hex
);
1735 else if (brushColour
!= "WHITE")
1736 clause
->AddAttributeValueString("brush_colour", brushColour
);
1738 if (m_brush
->GetStyle() != wxSOLID
)
1739 clause
->AddAttributeValue("brush_style", (long)m_brush
->GetStyle());
1744 int n_lines
= m_lines
.Number();
1747 wxExpr
*list
= new wxExpr(wxExprList
);
1748 wxNode
*node
= m_lines
.First();
1751 wxShape
*line
= (wxShape
*)node
->Data();
1752 wxExpr
*id_expr
= new wxExpr(line
->GetId());
1753 list
->Append(id_expr
);
1754 node
= node
->Next();
1756 clause
->AddAttributeValue("arcs", list
);
1759 // Miscellaneous members
1760 if (m_attachmentMode
!= 0)
1761 clause
->AddAttributeValue("use_attachments", (long)m_attachmentMode
);
1762 if (m_sensitivity
!= OP_ALL
)
1763 clause
->AddAttributeValue("sensitivity", (long)m_sensitivity
);
1764 if (!m_spaceAttachments
)
1765 clause
->AddAttributeValue("space_attachments", (long)m_spaceAttachments
);
1767 clause
->AddAttributeValue("fixed_width", (long)m_fixedWidth
);
1769 clause
->AddAttributeValue("fixed_height", (long)m_fixedHeight
);
1770 if (m_shadowMode
!= SHADOW_NONE
)
1771 clause
->AddAttributeValue("shadow_mode", (long)m_shadowMode
);
1772 if (m_centreResize
!= TRUE
)
1773 clause
->AddAttributeValue("centre_resize", (long)0);
1774 clause
->AddAttributeValue("maintain_aspect_ratio", (long) m_maintainAspectRatio
);
1775 if (m_highlighted
!= FALSE
)
1776 clause
->AddAttributeValue("hilite", (long)m_highlighted
);
1778 if (m_parent
) // For composite objects
1779 clause
->AddAttributeValue("parent", (long)m_parent
->GetId());
1781 if (m_rotation
!= 0.0)
1782 clause
->AddAttributeValue("rotation", m_rotation
);
1784 if (!this->IsKindOf(CLASSINFO(wxLineShape
)))
1786 clause
->AddAttributeValue("neck_length", (long) m_branchNeckLength
);
1787 clause
->AddAttributeValue("stem_length", (long) m_branchStemLength
);
1788 clause
->AddAttributeValue("branch_spacing", (long) m_branchSpacing
);
1789 clause
->AddAttributeValue("branch_style", (long) m_branchStyle
);
1792 // Write user-defined attachment points, if any
1793 if (m_attachmentPoints
.Number() > 0)
1795 wxExpr
*attachmentList
= new wxExpr(wxExprList
);
1796 wxNode
*node
= m_attachmentPoints
.First();
1799 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
1800 wxExpr
*pointExpr
= new wxExpr(wxExprList
);
1801 pointExpr
->Append(new wxExpr((long)point
->m_id
));
1802 pointExpr
->Append(new wxExpr(point
->m_x
));
1803 pointExpr
->Append(new wxExpr(point
->m_y
));
1804 attachmentList
->Append(pointExpr
);
1805 node
= node
->Next();
1807 clause
->AddAttributeValue("user_attachments", attachmentList
);
1810 // Write text regions
1811 WriteRegions(clause
);
1814 void wxShape::WriteRegions(wxExpr
*clause
)
1816 // Output regions as region1 = (...), region2 = (...), etc
1817 // and formatted text as text1 = (...), text2 = (...) etc.
1819 char regionNameBuf
[20];
1820 char textNameBuf
[20];
1821 wxNode
*node
= m_regions
.First();
1824 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
1825 sprintf(regionNameBuf
, "region%d", regionNo
);
1826 sprintf(textNameBuf
, "text%d", regionNo
);
1828 // Original text and region attributes:
1829 // region1 = (regionName regionText x y width height minWidth minHeight proportionX proportionY
1830 // formatMode fontSize fontFamily fontStyle fontWeight textColour)
1831 wxExpr
*regionExpr
= new wxExpr(wxExprList
);
1832 regionExpr
->Append(new wxExpr(wxExprString
, region
->m_regionName
));
1833 regionExpr
->Append(new wxExpr(wxExprString
, region
->m_regionText
));
1835 regionExpr
->Append(new wxExpr(region
->m_x
));
1836 regionExpr
->Append(new wxExpr(region
->m_y
));
1837 regionExpr
->Append(new wxExpr(region
->GetWidth()));
1838 regionExpr
->Append(new wxExpr(region
->GetHeight()));
1840 regionExpr
->Append(new wxExpr(region
->m_minWidth
));
1841 regionExpr
->Append(new wxExpr(region
->m_minHeight
));
1842 regionExpr
->Append(new wxExpr(region
->m_regionProportionX
));
1843 regionExpr
->Append(new wxExpr(region
->m_regionProportionY
));
1845 regionExpr
->Append(new wxExpr((long)region
->m_formatMode
));
1847 regionExpr
->Append(new wxExpr((long)(region
->m_font
? region
->m_font
->GetPointSize() : 10)));
1848 regionExpr
->Append(new wxExpr((long)(region
->m_font
? region
->m_font
->GetFamily() : wxDEFAULT
)));
1849 regionExpr
->Append(new wxExpr((long)(region
->m_font
? region
->m_font
->GetStyle() : wxDEFAULT
)));
1850 regionExpr
->Append(new wxExpr((long)(region
->m_font
? region
->m_font
->GetWeight() : wxNORMAL
)));
1851 regionExpr
->Append(new wxExpr(wxExprString
, region
->m_textColour
));
1853 // New members for pen colour/style
1854 regionExpr
->Append(new wxExpr(wxExprString
, region
->m_penColour
));
1855 regionExpr
->Append(new wxExpr((long)region
->m_penStyle
));
1858 // text1 = ((x y string) (x y string) ...)
1859 wxExpr
*textExpr
= new wxExpr(wxExprList
);
1861 wxNode
*textNode
= region
->m_formattedText
.First();
1864 wxShapeTextLine
*line
= (wxShapeTextLine
*)textNode
->Data();
1865 wxExpr
*list2
= new wxExpr(wxExprList
);
1866 list2
->Append(new wxExpr(line
->GetX()));
1867 list2
->Append(new wxExpr(line
->GetY()));
1868 list2
->Append(new wxExpr(wxExprString
, line
->GetText()));
1869 textExpr
->Append(list2
);
1870 textNode
= textNode
->Next();
1873 // Now add both attributes to the clause
1874 clause
->AddAttributeValue(regionNameBuf
, regionExpr
);
1875 clause
->AddAttributeValue(textNameBuf
, textExpr
);
1877 node
= node
->Next();
1882 void wxShape::ReadAttributes(wxExpr
*clause
)
1884 clause
->GetAttributeValue("id", m_id
);
1887 clause
->GetAttributeValue("x", m_xpos
);
1888 clause
->GetAttributeValue("y", m_ypos
);
1890 // Input text strings (FOR COMPATIBILITY WITH OLD FILES ONLY. SEE REGION CODE BELOW.)
1892 wxExpr
*strings
= clause
->AttributeValue("text");
1893 if (strings
&& strings
->Type() == wxExprList
)
1895 m_formatted
= TRUE
; // Assume text is formatted unless we prove otherwise
1896 wxExpr
*node
= strings
->value
.first
;
1899 wxExpr
*string_expr
= node
;
1902 wxString
the_string("");
1904 // string_expr can either be a string, or a list of
1905 // 3 elements: x, y, and string.
1906 if (string_expr
->Type() == wxExprString
)
1908 the_string
= string_expr
->StringValue();
1909 m_formatted
= FALSE
;
1911 else if (string_expr
->Type() == wxExprList
)
1913 wxExpr
*first
= string_expr
->value
.first
;
1914 wxExpr
*second
= first
? first
->next
: (wxExpr
*) NULL
;
1915 wxExpr
*third
= second
? second
->next
: (wxExpr
*) NULL
;
1917 if (first
&& second
&& third
&&
1918 (first
->Type() == wxExprReal
|| first
->Type() == wxExprInteger
) &&
1919 (second
->Type() == wxExprReal
|| second
->Type() == wxExprInteger
) &&
1920 third
->Type() == wxExprString
)
1922 if (first
->Type() == wxExprReal
)
1923 the_x
= first
->RealValue();
1924 else the_x
= (double)first
->IntegerValue();
1926 if (second
->Type() == wxExprReal
)
1927 the_y
= second
->RealValue();
1928 else the_y
= (double)second
->IntegerValue();
1930 the_string
= third
->StringValue();
1933 wxShapeTextLine
*line
=
1934 new wxShapeTextLine(the_x
, the_y
, (char*) (const char*) the_string
);
1935 m_text
.Append(line
);
1941 wxString pen_string
= "";
1942 wxString brush_string
= "";
1944 int pen_style
= wxSOLID
;
1945 int brush_style
= wxSOLID
;
1946 m_attachmentMode
= ATTACHMENT_MODE_NONE
;
1948 clause
->GetAttributeValue("pen_colour", pen_string
);
1949 clause
->GetAttributeValue("text_colour", m_textColourName
);
1951 SetTextColour(m_textColourName
);
1953 clause
->GetAttributeValue("region_name", m_regionName
);
1955 clause
->GetAttributeValue("brush_colour", brush_string
);
1956 clause
->GetAttributeValue("pen_width", pen_width
);
1957 clause
->GetAttributeValue("pen_style", pen_style
);
1958 clause
->GetAttributeValue("brush_style", brush_style
);
1960 int iVal
= (int) m_attachmentMode
;
1961 clause
->GetAttributeValue("use_attachments", iVal
);
1962 m_attachmentMode
= iVal
;
1964 clause
->GetAttributeValue("sensitivity", m_sensitivity
);
1966 iVal
= (int) m_spaceAttachments
;
1967 clause
->GetAttributeValue("space_attachments", iVal
);
1968 m_spaceAttachments
= (iVal
!= 0);
1970 iVal
= (int) m_fixedWidth
;
1971 clause
->GetAttributeValue("fixed_width", iVal
);
1972 m_fixedWidth
= (iVal
!= 0);
1974 iVal
= (int) m_fixedHeight
;
1975 clause
->GetAttributeValue("fixed_height", iVal
);
1976 m_fixedHeight
= (iVal
!= 0);
1978 clause
->GetAttributeValue("format_mode", m_formatMode
);
1979 clause
->GetAttributeValue("shadow_mode", m_shadowMode
);
1981 iVal
= m_branchNeckLength
;
1982 clause
->GetAttributeValue("neck_length", iVal
);
1983 m_branchNeckLength
= iVal
;
1985 iVal
= m_branchStemLength
;
1986 clause
->GetAttributeValue("stem_length", iVal
);
1987 m_branchStemLength
= iVal
;
1989 iVal
= m_branchSpacing
;
1990 clause
->GetAttributeValue("branch_spacing", iVal
);
1991 m_branchSpacing
= iVal
;
1993 clause
->GetAttributeValue("branch_style", m_branchStyle
);
1995 iVal
= (int) m_centreResize
;
1996 clause
->GetAttributeValue("centre_resize", iVal
);
1997 m_centreResize
= (iVal
!= 0);
1999 iVal
= (int) m_maintainAspectRatio
;
2000 clause
->GetAttributeValue("maintain_aspect_ratio", iVal
);
2001 m_maintainAspectRatio
= (iVal
!= 0);
2003 iVal
= (int) m_highlighted
;
2004 clause
->GetAttributeValue("hilite", iVal
);
2005 m_highlighted
= (iVal
!= 0);
2007 clause
->GetAttributeValue("rotation", m_rotation
);
2009 if (pen_string
== "")
2010 pen_string
= "BLACK";
2011 if (brush_string
== "")
2012 brush_string
= "WHITE";
2014 if (pen_string
.GetChar(0) == '#')
2016 wxColour
col(oglHexToColour(pen_string
.After('#')));
2017 m_pen
= wxThePenList
->FindOrCreatePen(col
, pen_width
, pen_style
);
2020 m_pen
= wxThePenList
->FindOrCreatePen(pen_string
, pen_width
, pen_style
);
2023 m_pen
= wxBLACK_PEN
;
2025 if (brush_string
.GetChar(0) == '#')
2027 wxColour
col(oglHexToColour(brush_string
.After('#')));
2028 m_brush
= wxTheBrushList
->FindOrCreateBrush(col
, brush_style
);
2031 m_brush
= wxTheBrushList
->FindOrCreateBrush(brush_string
, brush_style
);
2034 m_brush
= wxWHITE_BRUSH
;
2036 int point_size
= 10;
2037 clause
->GetAttributeValue("point_size", point_size
);
2038 SetFont(oglMatchFont(point_size
));
2040 // Read user-defined attachment points, if any
2041 wxExpr
*attachmentList
= clause
->AttributeValue("user_attachments");
2044 wxExpr
*pointExpr
= attachmentList
->GetFirst();
2047 wxExpr
*idExpr
= pointExpr
->Nth(0);
2048 wxExpr
*xExpr
= pointExpr
->Nth(1);
2049 wxExpr
*yExpr
= pointExpr
->Nth(2);
2050 if (idExpr
&& xExpr
&& yExpr
)
2052 wxAttachmentPoint
*point
= new wxAttachmentPoint
;
2053 point
->m_id
= (int)idExpr
->IntegerValue();
2054 point
->m_x
= xExpr
->RealValue();
2055 point
->m_y
= yExpr
->RealValue();
2056 m_attachmentPoints
.Append((wxObject
*)point
);
2058 pointExpr
= pointExpr
->GetNext();
2062 // Read text regions
2063 ReadRegions(clause
);
2066 void wxShape::ReadRegions(wxExpr
*clause
)
2070 // region1 = (regionName regionText x y width height minWidth minHeight proportionX proportionY
2071 // formatMode fontSize fontFamily fontStyle fontWeight textColour)
2073 char regionNameBuf
[20];
2074 char textNameBuf
[20];
2076 wxExpr
*regionExpr
= NULL
;
2077 wxExpr
*textExpr
= NULL
;
2078 sprintf(regionNameBuf
, "region%d", regionNo
);
2079 sprintf(textNameBuf
, "text%d", regionNo
);
2081 m_formatted
= TRUE
; // Assume text is formatted unless we prove otherwise
2083 while ((regionExpr
= clause
->AttributeValue(regionNameBuf
)))
2086 * Get the region information
2090 wxString
regionName("");
2091 wxString
regionText("");
2095 double height
= 0.0;
2096 double minWidth
= 5.0;
2097 double minHeight
= 5.0;
2098 double m_regionProportionX
= -1.0;
2099 double m_regionProportionY
= -1.0;
2100 int formatMode
= FORMAT_NONE
;
2102 int fontFamily
= wxSWISS
;
2103 int fontStyle
= wxNORMAL
;
2104 int fontWeight
= wxNORMAL
;
2105 wxString
regionTextColour("");
2106 wxString
penColour("");
2107 int penStyle
= wxSOLID
;
2109 if (regionExpr
->Type() == wxExprList
)
2111 wxExpr
*nameExpr
= regionExpr
->Nth(0);
2112 wxExpr
*textExpr
= regionExpr
->Nth(1);
2113 wxExpr
*xExpr
= regionExpr
->Nth(2);
2114 wxExpr
*yExpr
= regionExpr
->Nth(3);
2115 wxExpr
*widthExpr
= regionExpr
->Nth(4);
2116 wxExpr
*heightExpr
= regionExpr
->Nth(5);
2117 wxExpr
*minWidthExpr
= regionExpr
->Nth(6);
2118 wxExpr
*minHeightExpr
= regionExpr
->Nth(7);
2119 wxExpr
*propXExpr
= regionExpr
->Nth(8);
2120 wxExpr
*propYExpr
= regionExpr
->Nth(9);
2121 wxExpr
*formatExpr
= regionExpr
->Nth(10);
2122 wxExpr
*sizeExpr
= regionExpr
->Nth(11);
2123 wxExpr
*familyExpr
= regionExpr
->Nth(12);
2124 wxExpr
*styleExpr
= regionExpr
->Nth(13);
2125 wxExpr
*weightExpr
= regionExpr
->Nth(14);
2126 wxExpr
*colourExpr
= regionExpr
->Nth(15);
2127 wxExpr
*penColourExpr
= regionExpr
->Nth(16);
2128 wxExpr
*penStyleExpr
= regionExpr
->Nth(17);
2130 regionName
= nameExpr
->StringValue();
2131 regionText
= textExpr
->StringValue();
2133 x
= xExpr
->RealValue();
2134 y
= yExpr
->RealValue();
2136 width
= widthExpr
->RealValue();
2137 height
= heightExpr
->RealValue();
2139 minWidth
= minWidthExpr
->RealValue();
2140 minHeight
= minHeightExpr
->RealValue();
2142 m_regionProportionX
= propXExpr
->RealValue();
2143 m_regionProportionY
= propYExpr
->RealValue();
2145 formatMode
= (int) formatExpr
->IntegerValue();
2146 fontSize
= (int)sizeExpr
->IntegerValue();
2147 fontFamily
= (int)familyExpr
->IntegerValue();
2148 fontStyle
= (int)styleExpr
->IntegerValue();
2149 fontWeight
= (int)weightExpr
->IntegerValue();
2153 regionTextColour
= colourExpr
->StringValue();
2156 regionTextColour
= "BLACK";
2159 penColour
= penColourExpr
->StringValue();
2161 penStyle
= (int)penStyleExpr
->IntegerValue();
2163 wxFont
*font
= wxTheFontList
->FindOrCreateFont(fontSize
, fontFamily
, fontStyle
, fontWeight
);
2165 wxShapeRegion
*region
= new wxShapeRegion
;
2166 region
->SetProportions(m_regionProportionX
, m_regionProportionY
);
2167 region
->SetFont(font
);
2168 region
->SetSize(width
, height
);
2169 region
->SetPosition(x
, y
);
2170 region
->SetMinSize(minWidth
, minHeight
);
2171 region
->SetFormatMode(formatMode
);
2172 region
->SetPenStyle(penStyle
);
2173 if (penColour
!= "")
2174 region
->SetPenColour(penColour
);
2176 region
->m_textColour
= regionTextColour
;
2177 region
->m_regionText
= regionText
;
2178 region
->m_regionName
= regionName
;
2180 m_regions
.Append(region
);
2183 * Get the formatted text strings
2186 textExpr
= clause
->AttributeValue(textNameBuf
);
2187 if (textExpr
&& (textExpr
->Type() == wxExprList
))
2189 wxExpr
*node
= textExpr
->value
.first
;
2192 wxExpr
*string_expr
= node
;
2195 wxString
the_string("");
2197 // string_expr can either be a string, or a list of
2198 // 3 elements: x, y, and string.
2199 if (string_expr
->Type() == wxExprString
)
2201 the_string
= string_expr
->StringValue();
2202 m_formatted
= FALSE
;
2204 else if (string_expr
->Type() == wxExprList
)
2206 wxExpr
*first
= string_expr
->value
.first
;
2207 wxExpr
*second
= first
? first
->next
: (wxExpr
*) NULL
;
2208 wxExpr
*third
= second
? second
->next
: (wxExpr
*) NULL
;
2210 if (first
&& second
&& third
&&
2211 (first
->Type() == wxExprReal
|| first
->Type() == wxExprInteger
) &&
2212 (second
->Type() == wxExprReal
|| second
->Type() == wxExprInteger
) &&
2213 third
->Type() == wxExprString
)
2215 if (first
->Type() == wxExprReal
)
2216 the_x
= first
->RealValue();
2217 else the_x
= (double)first
->IntegerValue();
2219 if (second
->Type() == wxExprReal
)
2220 the_y
= second
->RealValue();
2221 else the_y
= (double)second
->IntegerValue();
2223 the_string
= third
->StringValue();
2228 wxShapeTextLine
*line
=
2229 new wxShapeTextLine(the_x
, the_y
, (char*) (const char*) the_string
);
2230 region
->m_formattedText
.Append(line
);
2237 sprintf(regionNameBuf
, "region%d", regionNo
);
2238 sprintf(textNameBuf
, "text%d", regionNo
);
2241 // Compatibility: check for no regions (old file).
2242 // Lines and divided rectangles must deal with this compatibility
2243 // theirselves. Composites _may_ not have any regions anyway.
2244 if ((m_regions
.Number() == 0) &&
2245 !this->IsKindOf(CLASSINFO(wxLineShape
)) && !this->IsKindOf(CLASSINFO(wxDividedShape
)) &&
2246 !this->IsKindOf(CLASSINFO(wxCompositeShape
)))
2248 wxShapeRegion
*newRegion
= new wxShapeRegion
;
2249 newRegion
->SetName("0");
2250 m_regions
.Append((wxObject
*)newRegion
);
2251 if (m_text
.Number() > 0)
2253 newRegion
->ClearText();
2254 wxNode
*node
= m_text
.First();
2257 wxShapeTextLine
*textLine
= (wxShapeTextLine
*)node
->Data();
2258 wxNode
*next
= node
->Next();
2259 newRegion
->GetFormattedText().Append((wxObject
*)textLine
);
2269 void wxShape::Copy(wxShape
& copy
)
2272 copy
.m_xpos
= m_xpos
;
2273 copy
.m_ypos
= m_ypos
;
2275 copy
.m_brush
= m_brush
;
2276 copy
.m_textColour
= m_textColour
;
2277 copy
.m_centreResize
= m_centreResize
;
2278 copy
.m_maintainAspectRatio
= m_maintainAspectRatio
;
2279 copy
.m_attachmentMode
= m_attachmentMode
;
2280 copy
.m_spaceAttachments
= m_spaceAttachments
;
2281 copy
.m_highlighted
= m_highlighted
;
2282 copy
.m_rotation
= m_rotation
;
2283 copy
.m_textColourName
= m_textColourName
;
2284 copy
.m_regionName
= m_regionName
;
2286 copy
.m_sensitivity
= m_sensitivity
;
2287 copy
.m_draggable
= m_draggable
;
2288 copy
.m_fixedWidth
= m_fixedWidth
;
2289 copy
.m_fixedHeight
= m_fixedHeight
;
2290 copy
.m_formatMode
= m_formatMode
;
2291 copy
.m_drawHandles
= m_drawHandles
;
2293 copy
.m_visible
= m_visible
;
2294 copy
.m_shadowMode
= m_shadowMode
;
2295 copy
.m_shadowOffsetX
= m_shadowOffsetX
;
2296 copy
.m_shadowOffsetY
= m_shadowOffsetY
;
2297 copy
.m_shadowBrush
= m_shadowBrush
;
2299 copy
.m_branchNeckLength
= m_branchNeckLength
;
2300 copy
.m_branchStemLength
= m_branchStemLength
;
2301 copy
.m_branchSpacing
= m_branchSpacing
;
2303 // Copy text regions
2304 copy
.ClearRegions();
2305 wxNode
*node
= m_regions
.First();
2308 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
2309 wxShapeRegion
*newRegion
= new wxShapeRegion(*region
);
2310 copy
.m_regions
.Append(newRegion
);
2311 node
= node
->Next();
2315 copy
.ClearAttachments();
2316 node
= m_attachmentPoints
.First();
2319 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
2320 wxAttachmentPoint
*newPoint
= new wxAttachmentPoint
;
2321 newPoint
->m_id
= point
->m_id
;
2322 newPoint
->m_x
= point
->m_x
;
2323 newPoint
->m_y
= point
->m_y
;
2324 copy
.m_attachmentPoints
.Append((wxObject
*)newPoint
);
2325 node
= node
->Next();
2329 copy
.m_lines
.Clear();
2330 node
= m_lines
.First();
2333 wxLineShape
* line
= (wxLineShape
*) node
->Data();
2334 copy
.m_lines
.Append(line
);
2335 node
= node
->Next();
2339 // Create and return a new, fully copied object.
2340 wxShape
*wxShape::CreateNewCopy(bool resetMapping
, bool recompute
)
2343 oglObjectCopyMapping
.Clear();
2345 wxShape
* newObject
= (wxShape
*) GetClassInfo()->CreateObject();
2347 wxASSERT( (newObject
!= NULL
) );
2348 wxASSERT( (newObject
->IsKindOf(CLASSINFO(wxShape
))) );
2352 if (GetEventHandler() != this)
2354 wxShapeEvtHandler
* newHandler
= GetEventHandler()->CreateNewCopy();
2355 newObject
->SetEventHandler(newHandler
);
2356 newObject
->SetPreviousHandler(NULL
);
2357 newHandler
->SetPreviousHandler(newObject
);
2358 newHandler
->SetShape(newObject
);
2362 newObject
->Recompute();
2366 // Does the copying for this object, including copying event
2367 // handler data if any. Calls the virtual Copy function.
2368 void wxShape::CopyWithHandler(wxShape
& copy
)
2372 if (GetEventHandler() != this)
2374 wxASSERT( copy
.GetEventHandler() != NULL
);
2375 wxASSERT( copy
.GetEventHandler() != (©
) );
2376 wxASSERT( GetEventHandler()->GetClassInfo() == copy
.GetEventHandler()->GetClassInfo() );
2377 GetEventHandler()->CopyData(* (copy
.GetEventHandler()));
2382 // Default - make 6 control points
2383 void wxShape::MakeControlPoints()
2385 double maxX
, maxY
, minX
, minY
;
2387 GetBoundingBoxMax(&maxX
, &maxY
);
2388 GetBoundingBoxMin(&minX
, &minY
);
2390 double widthMin
= (double)(minX
+ CONTROL_POINT_SIZE
+ 2);
2391 double heightMin
= (double)(minY
+ CONTROL_POINT_SIZE
+ 2);
2393 // Offsets from main object
2394 double top
= (double)(- (heightMin
/ 2.0));
2395 double bottom
= (double)(heightMin
/ 2.0 + (maxY
- minY
));
2396 double left
= (double)(- (widthMin
/ 2.0));
2397 double right
= (double)(widthMin
/ 2.0 + (maxX
- minX
));
2399 wxControlPoint
*control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, left
, top
,
2400 CONTROL_POINT_DIAGONAL
);
2401 m_canvas
->AddShape(control
);
2402 m_controlPoints
.Append(control
);
2404 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, 0, top
,
2405 CONTROL_POINT_VERTICAL
);
2406 m_canvas
->AddShape(control
);
2407 m_controlPoints
.Append(control
);
2409 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, right
, top
,
2410 CONTROL_POINT_DIAGONAL
);
2411 m_canvas
->AddShape(control
);
2412 m_controlPoints
.Append(control
);
2414 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, right
, 0,
2415 CONTROL_POINT_HORIZONTAL
);
2416 m_canvas
->AddShape(control
);
2417 m_controlPoints
.Append(control
);
2419 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, right
, bottom
,
2420 CONTROL_POINT_DIAGONAL
);
2421 m_canvas
->AddShape(control
);
2422 m_controlPoints
.Append(control
);
2424 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, 0, bottom
,
2425 CONTROL_POINT_VERTICAL
);
2426 m_canvas
->AddShape(control
);
2427 m_controlPoints
.Append(control
);
2429 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, left
, bottom
,
2430 CONTROL_POINT_DIAGONAL
);
2431 m_canvas
->AddShape(control
);
2432 m_controlPoints
.Append(control
);
2434 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, left
, 0,
2435 CONTROL_POINT_HORIZONTAL
);
2436 m_canvas
->AddShape(control
);
2437 m_controlPoints
.Append(control
);
2441 void wxShape::MakeMandatoryControlPoints()
2443 wxNode
*node
= m_children
.First();
2446 wxShape
*child
= (wxShape
*)node
->Data();
2447 child
->MakeMandatoryControlPoints();
2448 node
= node
->Next();
2452 void wxShape::ResetMandatoryControlPoints()
2454 wxNode
*node
= m_children
.First();
2457 wxShape
*child
= (wxShape
*)node
->Data();
2458 child
->ResetMandatoryControlPoints();
2459 node
= node
->Next();
2463 void wxShape::ResetControlPoints()
2465 ResetMandatoryControlPoints();
2467 if (m_controlPoints
.Number() < 1)
2470 double maxX
, maxY
, minX
, minY
;
2472 GetBoundingBoxMax(&maxX
, &maxY
);
2473 GetBoundingBoxMin(&minX
, &minY
);
2475 double widthMin
= (double)(minX
+ CONTROL_POINT_SIZE
+ 2);
2476 double heightMin
= (double)(minY
+ CONTROL_POINT_SIZE
+ 2);
2478 // Offsets from main object
2479 double top
= (double)(- (heightMin
/ 2.0));
2480 double bottom
= (double)(heightMin
/ 2.0 + (maxY
- minY
));
2481 double left
= (double)(- (widthMin
/ 2.0));
2482 double right
= (double)(widthMin
/ 2.0 + (maxX
- minX
));
2484 wxNode
*node
= m_controlPoints
.First();
2485 wxControlPoint
*control
= (wxControlPoint
*)node
->Data();
2486 control
->m_xoffset
= left
; control
->m_yoffset
= top
;
2488 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2489 control
->m_xoffset
= 0; control
->m_yoffset
= top
;
2491 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2492 control
->m_xoffset
= right
; control
->m_yoffset
= top
;
2494 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2495 control
->m_xoffset
= right
; control
->m_yoffset
= 0;
2497 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2498 control
->m_xoffset
= right
; control
->m_yoffset
= bottom
;
2500 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2501 control
->m_xoffset
= 0; control
->m_yoffset
= bottom
;
2503 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2504 control
->m_xoffset
= left
; control
->m_yoffset
= bottom
;
2506 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2507 control
->m_xoffset
= left
; control
->m_yoffset
= 0;
2510 void wxShape::DeleteControlPoints(wxDC
*dc
)
2512 wxNode
*node
= m_controlPoints
.First();
2515 wxControlPoint
*control
= (wxControlPoint
*)node
->Data();
2517 control
->GetEventHandler()->OnErase(*dc
);
2518 m_canvas
->RemoveShape(control
);
2521 node
= m_controlPoints
.First();
2523 // Children of divisions are contained objects,
2525 if (!IsKindOf(CLASSINFO(wxDivisionShape
)))
2527 node
= m_children
.First();
2530 wxShape
*child
= (wxShape
*)node
->Data();
2531 child
->DeleteControlPoints(dc
);
2532 node
= node
->Next();
2537 void wxShape::OnDrawControlPoints(wxDC
& dc
)
2542 dc
.SetBrush(* wxBLACK_BRUSH
);
2543 dc
.SetPen(* wxBLACK_PEN
);
2545 wxNode
*node
= m_controlPoints
.First();
2548 wxControlPoint
*control
= (wxControlPoint
*)node
->Data();
2550 node
= node
->Next();
2552 // Children of divisions are contained objects,
2554 // This test bypasses the type facility for speed
2555 // (critical when drawing)
2556 if (!IsKindOf(CLASSINFO(wxDivisionShape
)))
2558 node
= m_children
.First();
2561 wxShape
*child
= (wxShape
*)node
->Data();
2562 child
->GetEventHandler()->OnDrawControlPoints(dc
);
2563 node
= node
->Next();
2568 void wxShape::OnEraseControlPoints(wxDC
& dc
)
2570 wxNode
*node
= m_controlPoints
.First();
2573 wxControlPoint
*control
= (wxControlPoint
*)node
->Data();
2575 node
= node
->Next();
2577 if (!IsKindOf(CLASSINFO(wxDivisionShape
)))
2579 node
= m_children
.First();
2582 wxShape
*child
= (wxShape
*)node
->Data();
2583 child
->GetEventHandler()->OnEraseControlPoints(dc
);
2584 node
= node
->Next();
2589 void wxShape::Select(bool select
, wxDC
* dc
)
2591 m_selected
= select
;
2594 MakeControlPoints();
2595 // Children of divisions are contained objects,
2597 if (!IsKindOf(CLASSINFO(wxDivisionShape
)))
2599 wxNode
*node
= m_children
.First();
2602 wxShape
*child
= (wxShape
*)node
->Data();
2603 child
->MakeMandatoryControlPoints();
2604 node
= node
->Next();
2608 GetEventHandler()->OnDrawControlPoints(*dc
);
2612 DeleteControlPoints(dc
);
2613 if (!IsKindOf(CLASSINFO(wxDivisionShape
)))
2615 wxNode
*node
= m_children
.First();
2618 wxShape
*child
= (wxShape
*)node
->Data();
2619 child
->DeleteControlPoints(dc
);
2620 node
= node
->Next();
2626 bool wxShape::Selected() const
2631 bool wxShape::AncestorSelected() const
2633 if (m_selected
) return TRUE
;
2637 return GetParent()->AncestorSelected();
2640 int wxShape::GetNumberOfAttachments() const
2642 // Should return the MAXIMUM attachment point id here,
2643 // so higher-level functions can iterate through all attachments,
2644 // even if they're not contiguous.
2645 if (m_attachmentPoints
.Number() == 0)
2650 wxNode
*node
= m_attachmentPoints
.First();
2653 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
2654 if (point
->m_id
> maxN
)
2656 node
= node
->Next();
2662 bool wxShape::AttachmentIsValid(int attachment
) const
2664 if (m_attachmentPoints
.Number() == 0)
2666 return ((attachment
>= 0) && (attachment
< 4)) ;
2669 wxNode
*node
= m_attachmentPoints
.First();
2672 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
2673 if (point
->m_id
== attachment
)
2675 node
= node
->Next();
2680 bool wxShape::GetAttachmentPosition(int attachment
, double *x
, double *y
,
2681 int nth
, int no_arcs
, wxLineShape
*line
)
2683 if (m_attachmentMode
== ATTACHMENT_MODE_NONE
)
2685 *x
= m_xpos
; *y
= m_ypos
;
2688 else if (m_attachmentMode
== ATTACHMENT_MODE_BRANCHING
)
2690 wxRealPoint pt
, stemPt
;
2691 GetBranchingAttachmentPoint(attachment
, nth
, pt
, stemPt
);
2696 else if (m_attachmentMode
== ATTACHMENT_MODE_EDGE
)
2698 if (m_attachmentPoints
.Number() > 0)
2700 wxNode
*node
= m_attachmentPoints
.First();
2703 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
2704 if (point
->m_id
== attachment
)
2706 *x
= (double)(m_xpos
+ point
->m_x
);
2707 *y
= (double)(m_ypos
+ point
->m_y
);
2710 node
= node
->Next();
2712 *x
= m_xpos
; *y
= m_ypos
;
2717 // Assume is rectangular
2719 GetBoundingBoxMax(&w
, &h
);
2720 double top
= (double)(m_ypos
+ h
/2.0);
2721 double bottom
= (double)(m_ypos
- h
/2.0);
2722 double left
= (double)(m_xpos
- w
/2.0);
2723 double right
= (double)(m_xpos
+ w
/2.0);
2725 bool isEnd
= (line
&& line
->IsEnd(this));
2727 int physicalAttachment
= LogicalToPhysicalAttachment(attachment
);
2730 switch (physicalAttachment
)
2734 wxRealPoint pt
= CalcSimpleAttachment(wxRealPoint(left
, bottom
), wxRealPoint(right
, bottom
),
2735 nth
, no_arcs
, line
);
2737 *x
= pt
.x
; *y
= pt
.y
;
2742 wxRealPoint pt
= CalcSimpleAttachment(wxRealPoint(right
, bottom
), wxRealPoint(right
, top
),
2743 nth
, no_arcs
, line
);
2745 *x
= pt
.x
; *y
= pt
.y
;
2750 wxRealPoint pt
= CalcSimpleAttachment(wxRealPoint(left
, top
), wxRealPoint(right
, top
),
2751 nth
, no_arcs
, line
);
2753 *x
= pt
.x
; *y
= pt
.y
;
2758 wxRealPoint pt
= CalcSimpleAttachment(wxRealPoint(left
, bottom
), wxRealPoint(left
, top
),
2759 nth
, no_arcs
, line
);
2761 *x
= pt
.x
; *y
= pt
.y
;
2776 void wxShape::GetBoundingBoxMax(double *w
, double *h
)
2779 GetBoundingBoxMin(&ww
, &hh
);
2780 if (m_shadowMode
!= SHADOW_NONE
)
2782 ww
+= m_shadowOffsetX
;
2783 hh
+= m_shadowOffsetY
;
2789 // Returns TRUE if image is a descendant of this composite
2790 bool wxShape::HasDescendant(wxShape
*image
)
2794 wxNode
*node
= m_children
.First();
2797 wxShape
*child
= (wxShape
*)node
->Data();
2798 bool ans
= child
->HasDescendant(image
);
2801 node
= node
->Next();
2806 // Clears points from a list of wxRealPoints, and clears list
2807 void wxShape::ClearPointList(wxList
& list
)
2809 wxNode
* node
= list
.First();
2812 wxRealPoint
* pt
= (wxRealPoint
*) node
->Data();
2815 node
= node
->Next();
2820 // Assuming the attachment lies along a vertical or horizontal line,
2821 // calculate the position on that point.
2822 wxRealPoint
wxShape::CalcSimpleAttachment(const wxRealPoint
& pt1
, const wxRealPoint
& pt2
,
2823 int nth
, int noArcs
, wxLineShape
* line
)
2825 bool isEnd
= (line
&& line
->IsEnd(this));
2827 // Are we horizontal or vertical?
2828 bool isHorizontal
= (oglRoughlyEqual(pt1
.y
, pt2
.y
) == TRUE
);
2834 wxRealPoint firstPoint
, secondPoint
;
2846 if (m_spaceAttachments
)
2848 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
2850 // Align line according to the next handle along
2851 wxRealPoint
*point
= line
->GetNextControlPoint(this);
2852 if (point
->x
< firstPoint
.x
)
2854 else if (point
->x
> secondPoint
.x
)
2860 x
= firstPoint
.x
+ (nth
+ 1)*(secondPoint
.x
- firstPoint
.x
)/(noArcs
+ 1);
2862 else x
= (secondPoint
.x
- firstPoint
.x
)/2.0; // Midpoint
2868 wxASSERT( oglRoughlyEqual(pt1
.x
, pt2
.x
) == TRUE
);
2870 wxRealPoint firstPoint
, secondPoint
;
2882 if (m_spaceAttachments
)
2884 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
2886 // Align line according to the next handle along
2887 wxRealPoint
*point
= line
->GetNextControlPoint(this);
2888 if (point
->y
< firstPoint
.y
)
2890 else if (point
->y
> secondPoint
.y
)
2896 y
= firstPoint
.y
+ (nth
+ 1)*(secondPoint
.y
- firstPoint
.y
)/(noArcs
+ 1);
2898 else y
= (secondPoint
.y
- firstPoint
.y
)/2.0; // Midpoint
2903 return wxRealPoint(x
, y
);
2906 // Return the zero-based position in m_lines of line.
2907 int wxShape::GetLinePosition(wxLineShape
* line
)
2910 for (i
= 0; i
< m_lines
.Number(); i
++)
2911 if ((wxLineShape
*) (m_lines
.Nth(i
)->Data()) == line
)
2921 // shoulder1 ->---------<- shoulder2
2923 // <- branching attachment point N-1
2925 // This function gets information about where branching connections go.
2926 // Returns FALSE if there are no lines at this attachment.
2927 bool wxShape::GetBranchingAttachmentInfo(int attachment
, wxRealPoint
& root
, wxRealPoint
& neck
,
2928 wxRealPoint
& shoulder1
, wxRealPoint
& shoulder2
)
2930 int physicalAttachment
= LogicalToPhysicalAttachment(attachment
);
2932 // Number of lines at this attachment.
2933 int lineCount
= GetAttachmentLineCount(attachment
);
2938 int totalBranchLength
= m_branchSpacing
* (lineCount
- 1);
2940 root
= GetBranchingAttachmentRoot(attachment
);
2942 // Assume that we have attachment points 0 to 3: top, right, bottom, left.
2943 switch (physicalAttachment
)
2948 neck
.y
= root
.y
- m_branchNeckLength
;
2950 shoulder1
.x
= root
.x
- (totalBranchLength
/2.0) ;
2951 shoulder2
.x
= root
.x
+ (totalBranchLength
/2.0) ;
2953 shoulder1
.y
= neck
.y
;
2954 shoulder2
.y
= neck
.y
;
2959 neck
.x
= root
.x
+ m_branchNeckLength
;
2962 shoulder1
.x
= neck
.x
;
2963 shoulder2
.x
= neck
.x
;
2965 shoulder1
.y
= neck
.y
- (totalBranchLength
/2.0) ;
2966 shoulder2
.y
= neck
.y
+ (totalBranchLength
/2.0) ;
2972 neck
.y
= root
.y
+ m_branchNeckLength
;
2974 shoulder1
.x
= root
.x
- (totalBranchLength
/2.0) ;
2975 shoulder2
.x
= root
.x
+ (totalBranchLength
/2.0) ;
2977 shoulder1
.y
= neck
.y
;
2978 shoulder2
.y
= neck
.y
;
2983 neck
.x
= root
.x
- m_branchNeckLength
;
2986 shoulder1
.x
= neck
.x
;
2987 shoulder2
.x
= neck
.x
;
2989 shoulder1
.y
= neck
.y
- (totalBranchLength
/2.0) ;
2990 shoulder2
.y
= neck
.y
+ (totalBranchLength
/2.0) ;
2995 wxFAIL_MSG( "Unrecognised attachment point in GetBranchingAttachmentInfo." );
3002 // n is the number of the adjoining line, from 0 to N-1 where N is the number of lines
3003 // at this attachment point.
3004 // Get the attachment point where the arc joins the stem, and also the point where the
3005 // the stem meets the shoulder.
3006 bool wxShape::GetBranchingAttachmentPoint(int attachment
, int n
, wxRealPoint
& pt
, wxRealPoint
& stemPt
)
3008 int physicalAttachment
= LogicalToPhysicalAttachment(attachment
);
3010 wxRealPoint root
, neck
, shoulder1
, shoulder2
;
3011 GetBranchingAttachmentInfo(attachment
, root
, neck
, shoulder1
, shoulder2
);
3013 // Assume that we have attachment points 0 to 3: top, right, bottom, left.
3014 switch (physicalAttachment
)
3018 pt
.y
= neck
.y
- m_branchStemLength
;
3019 pt
.x
= shoulder1
.x
+ n
*m_branchSpacing
;
3027 pt
.y
= neck
.y
+ m_branchStemLength
;
3028 pt
.x
= shoulder1
.x
+ n
*m_branchSpacing
;
3036 pt
.x
= neck
.x
+ m_branchStemLength
;
3037 pt
.y
= shoulder1
.y
+ n
*m_branchSpacing
;
3045 pt
.x
= neck
.x
- m_branchStemLength
;
3046 pt
.y
= shoulder1
.y
+ n
*m_branchSpacing
;
3054 wxFAIL_MSG( "Unrecognised attachment point in GetBranchingAttachmentPoint." );
3062 // Get the number of lines at this attachment position.
3063 int wxShape::GetAttachmentLineCount(int attachment
) const
3066 wxNode
* node
= m_lines
.First();
3069 wxLineShape
* lineShape
= (wxLineShape
*) node
->Data();
3070 if ((lineShape
->GetFrom() == this) && (lineShape
->GetAttachmentFrom() == attachment
))
3072 else if ((lineShape
->GetTo() == this) && (lineShape
->GetAttachmentTo() == attachment
))
3075 node
= node
->Next();
3080 // This function gets the root point at the given attachment.
3081 wxRealPoint
wxShape::GetBranchingAttachmentRoot(int attachment
)
3083 int physicalAttachment
= LogicalToPhysicalAttachment(attachment
);
3087 double width
, height
;
3088 GetBoundingBoxMax(& width
, & height
);
3090 // Assume that we have attachment points 0 to 3: top, right, bottom, left.
3091 switch (physicalAttachment
)
3096 root
.y
= GetY() - height
/2.0;
3101 root
.x
= GetX() + width
/2.0;
3108 root
.y
= GetY() + height
/2.0;
3113 root
.x
= GetX() - width
/2.0;
3119 wxFAIL_MSG( "Unrecognised attachment point in GetBranchingAttachmentRoot." );
3126 // Draw or erase the branches (not the actual arcs though)
3127 void wxShape::OnDrawBranches(wxDC
& dc
, int attachment
, bool erase
)
3129 int count
= GetAttachmentLineCount(attachment
);
3133 wxRealPoint root
, neck
, shoulder1
, shoulder2
;
3134 GetBranchingAttachmentInfo(attachment
, root
, neck
, shoulder1
, shoulder2
);
3138 dc
.SetPen(*wxWHITE_PEN
);
3139 dc
.SetBrush(*wxWHITE_BRUSH
);
3143 dc
.SetPen(*wxBLACK_PEN
);
3144 dc
.SetBrush(*wxBLACK_BRUSH
);
3148 dc
.DrawLine((long) root
.x
, (long) root
.y
, (long) neck
.x
, (long) neck
.y
);
3152 // Draw shoulder-to-shoulder line
3153 dc
.DrawLine((long) shoulder1
.x
, (long) shoulder1
.y
, (long) shoulder2
.x
, (long) shoulder2
.y
);
3155 // Draw all the little branches
3157 for (i
= 0; i
< count
; i
++)
3159 wxRealPoint pt
, stemPt
;
3160 GetBranchingAttachmentPoint(attachment
, i
, pt
, stemPt
);
3161 dc
.DrawLine((long) stemPt
.x
, (long) stemPt
.y
, (long) pt
.x
, (long) pt
.y
);
3163 if ((GetBranchStyle() & BRANCHING_ATTACHMENT_BLOB
) && (count
> 1))
3166 // dc.DrawEllipse((long) (stemPt.x + 0.5 - (blobSize/2.0)), (long) (stemPt.y + 0.5 - (blobSize/2.0)), blobSize, blobSize);
3167 dc
.DrawEllipse((long) (stemPt
.x
- (blobSize
/2.0)), (long) (stemPt
.y
- (blobSize
/2.0)), blobSize
, blobSize
);
3172 // Draw or erase the branches (not the actual arcs though)
3173 void wxShape::OnDrawBranches(wxDC
& dc
, bool erase
)
3175 if (m_attachmentMode
!= ATTACHMENT_MODE_BRANCHING
)
3178 int count
= GetNumberOfAttachments();
3180 for (i
= 0; i
< count
; i
++)
3181 OnDrawBranches(dc
, i
, erase
);
3184 // Only get the attachment position at the _edge_ of the shape, ignoring
3185 // branching mode. This is used e.g. to indicate the edge of interest, not the point
3186 // on the attachment branch.
3187 bool wxShape::GetAttachmentPositionEdge(int attachment
, double *x
, double *y
,
3188 int nth
, int no_arcs
, wxLineShape
*line
)
3190 int oldMode
= m_attachmentMode
;
3192 // Calculate as if to edge, not branch
3193 if (m_attachmentMode
== ATTACHMENT_MODE_BRANCHING
)
3194 m_attachmentMode
= ATTACHMENT_MODE_EDGE
;
3195 bool success
= GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
3196 m_attachmentMode
= oldMode
;
3201 // Rotate the standard attachment point from physical (0 is always North)
3202 // to logical (0 -> 1 if rotated by 90 degrees)
3203 int wxShape::PhysicalToLogicalAttachment(int physicalAttachment
) const
3205 const double pi
= 3.1415926535897932384626433832795 ;
3207 if (oglRoughlyEqual(GetRotation(), 0.0))
3209 i
= physicalAttachment
;
3211 else if (oglRoughlyEqual(GetRotation(), (pi
/2.0)))
3213 i
= physicalAttachment
- 1;
3215 else if (oglRoughlyEqual(GetRotation(), pi
))
3217 i
= physicalAttachment
- 2;
3219 else if (oglRoughlyEqual(GetRotation(), (3.0*pi
/2.0)))
3221 i
= physicalAttachment
- 3;
3224 // Can't handle -- assume the same.
3225 return physicalAttachment
;
3233 // Rotate the standard attachment point from logical
3234 // to physical (0 is always North)
3235 int wxShape::LogicalToPhysicalAttachment(int logicalAttachment
) const
3237 const double pi
= 3.1415926535897932384626433832795 ;
3239 if (oglRoughlyEqual(GetRotation(), 0.0))
3241 i
= logicalAttachment
;
3243 else if (oglRoughlyEqual(GetRotation(), (pi
/2.0)))
3245 i
= logicalAttachment
+ 1;
3247 else if (oglRoughlyEqual(GetRotation(), pi
))
3249 i
= logicalAttachment
+ 2;
3251 else if (oglRoughlyEqual(GetRotation(), (3.0*pi
/2.0)))
3253 i
= logicalAttachment
+ 3;
3256 // Can't handle -- assume the same.
3257 return logicalAttachment
;
3265 void wxShape::Rotate(double WXUNUSED(x
), double WXUNUSED(y
), double theta
)
3267 const double pi
= 3.1415926535897932384626433832795 ;
3269 if (m_rotation
< 0.0)
3273 else if (m_rotation
> 2*pi
)
3280 wxPen
wxShape::GetBackgroundPen()
3284 wxColour c
= GetCanvas()->GetBackgroundColour();
3285 return wxPen(c
, 1, wxSOLID
);
3287 return * g_oglWhiteBackgroundPen
;
3291 wxBrush
wxShape::GetBackgroundBrush()
3295 wxColour c
= GetCanvas()->GetBackgroundColour();
3296 return wxBrush(c
, wxSOLID
);
3298 return * g_oglWhiteBackgroundBrush
;