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>
37 #include <wx/ogl/basic.h>
38 #include <wx/ogl/basicp.h>
39 #include <wx/ogl/composit.h>
40 #include <wx/ogl/lines.h>
41 #include <wx/ogl/canvas.h>
42 #include <wx/ogl/divided.h>
43 #include <wx/ogl/misc.h>
45 // Control point types
46 // Rectangle and most other shapes
47 #define CONTROL_POINT_VERTICAL 1
48 #define CONTROL_POINT_HORIZONTAL 2
49 #define CONTROL_POINT_DIAGONAL 3
52 #define CONTROL_POINT_ENDPOINT_TO 4
53 #define CONTROL_POINT_ENDPOINT_FROM 5
54 #define CONTROL_POINT_LINE 6
56 IMPLEMENT_DYNAMIC_CLASS(wxShapeTextLine
, wxObject
)
57 IMPLEMENT_DYNAMIC_CLASS(wxAttachmentPoint
, wxObject
)
59 wxShapeTextLine::wxShapeTextLine(double the_x
, double the_y
, const wxString
& the_line
)
61 m_x
= the_x
; m_y
= the_y
; m_line
= the_line
;
64 wxShapeTextLine::~wxShapeTextLine()
68 IMPLEMENT_ABSTRACT_CLASS(wxShapeEvtHandler
, wxObject
)
70 wxShapeEvtHandler::wxShapeEvtHandler(wxShapeEvtHandler
*prev
, wxShape
*shape
)
72 m_previousHandler
= prev
;
73 m_handlerShape
= shape
;
76 wxShapeEvtHandler::~wxShapeEvtHandler()
80 // Creates a copy of this event handler.
81 wxShapeEvtHandler
* wxShapeEvtHandler::CreateNewCopy()
83 wxShapeEvtHandler
* newObject
= (wxShapeEvtHandler
*) GetClassInfo()->CreateObject();
85 wxASSERT( (newObject
!= NULL
) );
86 wxASSERT( (newObject
->IsKindOf(CLASSINFO(wxShapeEvtHandler
))) );
88 newObject
->m_previousHandler
= newObject
;
96 void wxShapeEvtHandler::OnDelete()
98 if (this != GetShape())
102 void wxShapeEvtHandler::OnDraw(wxDC
& dc
)
104 if (m_previousHandler
)
105 m_previousHandler
->OnDraw(dc
);
108 void wxShapeEvtHandler::OnMoveLinks(wxDC
& dc
)
110 if (m_previousHandler
)
111 m_previousHandler
->OnMoveLinks(dc
);
114 void wxShapeEvtHandler::OnMoveLink(wxDC
& dc
, bool moveControlPoints
)
116 if (m_previousHandler
)
117 m_previousHandler
->OnMoveLink(dc
, moveControlPoints
);
120 void wxShapeEvtHandler::OnDrawContents(wxDC
& dc
)
122 if (m_previousHandler
)
123 m_previousHandler
->OnDrawContents(dc
);
126 void wxShapeEvtHandler::OnDrawBranches(wxDC
& dc
, bool erase
)
128 if (m_previousHandler
)
129 m_previousHandler
->OnDrawBranches(dc
, erase
);
132 void wxShapeEvtHandler::OnSize(double x
, double y
)
134 if (m_previousHandler
)
135 m_previousHandler
->OnSize(x
, y
);
138 bool wxShapeEvtHandler::OnMovePre(wxDC
& dc
, double x
, double y
, double old_x
, double old_y
, bool display
)
140 if (m_previousHandler
)
141 return m_previousHandler
->OnMovePre(dc
, x
, y
, old_x
, old_y
, display
);
146 void wxShapeEvtHandler::OnMovePost(wxDC
& dc
, double x
, double y
, double old_x
, double old_y
, bool display
)
148 if (m_previousHandler
)
149 m_previousHandler
->OnMovePost(dc
, x
, y
, old_x
, old_y
, display
);
152 void wxShapeEvtHandler::OnErase(wxDC
& dc
)
154 if (m_previousHandler
)
155 m_previousHandler
->OnErase(dc
);
158 void wxShapeEvtHandler::OnEraseContents(wxDC
& dc
)
160 if (m_previousHandler
)
161 m_previousHandler
->OnEraseContents(dc
);
164 void wxShapeEvtHandler::OnHighlight(wxDC
& dc
)
166 if (m_previousHandler
)
167 m_previousHandler
->OnHighlight(dc
);
170 void wxShapeEvtHandler::OnLeftClick(double x
, double y
, int keys
, int attachment
)
172 if (m_previousHandler
)
173 m_previousHandler
->OnLeftClick(x
, y
, keys
, attachment
);
176 void wxShapeEvtHandler::OnLeftDoubleClick(double x
, double y
, int keys
, int attachment
)
178 if (m_previousHandler
)
179 m_previousHandler
->OnLeftDoubleClick(x
, y
, keys
, attachment
);
182 void wxShapeEvtHandler::OnRightClick(double x
, double y
, int keys
, int attachment
)
184 if (m_previousHandler
)
185 m_previousHandler
->OnRightClick(x
, y
, keys
, attachment
);
188 void wxShapeEvtHandler::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
190 if (m_previousHandler
)
191 m_previousHandler
->OnDragLeft(draw
, x
, y
, keys
, attachment
);
194 void wxShapeEvtHandler::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
196 if (m_previousHandler
)
197 m_previousHandler
->OnBeginDragLeft(x
, y
, keys
, attachment
);
200 void wxShapeEvtHandler::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
202 if (m_previousHandler
)
203 m_previousHandler
->OnEndDragLeft(x
, y
, keys
, attachment
);
206 void wxShapeEvtHandler::OnDragRight(bool draw
, double x
, double y
, int keys
, int attachment
)
208 if (m_previousHandler
)
209 m_previousHandler
->OnDragRight(draw
, x
, y
, keys
, attachment
);
212 void wxShapeEvtHandler::OnBeginDragRight(double x
, double y
, int keys
, int attachment
)
214 if (m_previousHandler
)
215 m_previousHandler
->OnBeginDragRight(x
, y
, keys
, attachment
);
218 void wxShapeEvtHandler::OnEndDragRight(double x
, double y
, int keys
, int attachment
)
220 if (m_previousHandler
)
221 m_previousHandler
->OnEndDragRight(x
, y
, keys
, attachment
);
224 // Control points ('handles') redirect control to the actual shape, to make it easier
225 // to override sizing behaviour.
226 void wxShapeEvtHandler::OnSizingDragLeft(wxControlPoint
* pt
, bool draw
, double x
, double y
, int keys
, int attachment
)
228 if (m_previousHandler
)
229 m_previousHandler
->OnSizingDragLeft(pt
, draw
, x
, y
, keys
, attachment
);
232 void wxShapeEvtHandler::OnSizingBeginDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int attachment
)
234 if (m_previousHandler
)
235 m_previousHandler
->OnSizingBeginDragLeft(pt
, x
, y
, keys
, attachment
);
238 void wxShapeEvtHandler::OnSizingEndDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int attachment
)
240 if (m_previousHandler
)
241 m_previousHandler
->OnSizingEndDragLeft(pt
, x
, y
, keys
, attachment
);
244 void wxShapeEvtHandler::OnDrawOutline(wxDC
& dc
, double x
, double y
, double w
, double h
)
246 if (m_previousHandler
)
247 m_previousHandler
->OnDrawOutline(dc
, x
, y
, w
, h
);
250 void wxShapeEvtHandler::OnDrawControlPoints(wxDC
& dc
)
252 if (m_previousHandler
)
253 m_previousHandler
->OnDrawControlPoints(dc
);
256 void wxShapeEvtHandler::OnEraseControlPoints(wxDC
& dc
)
258 if (m_previousHandler
)
259 m_previousHandler
->OnEraseControlPoints(dc
);
262 // Can override this to prevent or intercept line reordering.
263 void wxShapeEvtHandler::OnChangeAttachment(int attachment
, wxLineShape
* line
, wxList
& ordering
)
265 if (m_previousHandler
)
266 m_previousHandler
->OnChangeAttachment(attachment
, line
, ordering
);
269 IMPLEMENT_ABSTRACT_CLASS(wxShape
, wxShapeEvtHandler
)
271 wxShape::wxShape(wxShapeCanvas
*can
)
273 m_eventHandler
= this;
278 m_xpos
= 0.0; m_ypos
= 0.0;
279 m_pen
= g_oglBlackPen
;
280 m_brush
= wxWHITE_BRUSH
;
281 m_font
= g_oglNormalFont
;
282 m_textColour
= wxBLACK
;
283 m_textColourName
= wxT("BLACK");
286 m_attachmentMode
= ATTACHMENT_MODE_NONE
;
287 m_spaceAttachments
= TRUE
;
288 m_disableLabel
= FALSE
;
289 m_fixedWidth
= FALSE
;
290 m_fixedHeight
= FALSE
;
291 m_drawHandles
= TRUE
;
292 m_sensitivity
= OP_ALL
;
295 m_formatMode
= FORMAT_CENTRE_HORIZ
| FORMAT_CENTRE_VERT
;
296 m_shadowMode
= SHADOW_NONE
;
299 m_shadowBrush
= wxBLACK_BRUSH
;
302 m_regionName
= wxT("0");
303 m_centreResize
= TRUE
;
304 m_maintainAspectRatio
= FALSE
;
305 m_highlighted
= FALSE
;
307 m_branchNeckLength
= 10;
308 m_branchStemLength
= 10;
309 m_branchSpacing
= 10;
310 m_branchStyle
= BRANCHING_ATTACHMENT_NORMAL
;
312 // Set up a default region. Much of the above will be put into
313 // the region eventually (the duplication is for compatibility)
314 wxShapeRegion
*region
= new wxShapeRegion
;
315 m_regions
.Append(region
);
316 region
->SetName(wxT("0"));
317 region
->SetFont(g_oglNormalFont
);
318 region
->SetFormatMode(FORMAT_CENTRE_HORIZ
| FORMAT_CENTRE_VERT
);
319 region
->SetColour(wxT("BLACK"));
325 m_parent
->GetChildren().DeleteObject(this);
332 m_canvas
->RemoveShape(this);
334 GetEventHandler()->OnDelete();
337 void wxShape::SetHighlight(bool hi
, bool recurse
)
342 wxNode
*node
= m_children
.First();
345 wxShape
*child
= (wxShape
*)node
->Data();
346 child
->SetHighlight(hi
, recurse
);
352 void wxShape::SetSensitivityFilter(int sens
, bool recursive
)
354 if (sens
& OP_DRAG_LEFT
)
359 m_sensitivity
= sens
;
362 wxNode
*node
= m_children
.First();
365 wxShape
*obj
= (wxShape
*)node
->Data();
366 obj
->SetSensitivityFilter(sens
, TRUE
);
372 void wxShape::SetDraggable(bool drag
, bool recursive
)
376 m_sensitivity
|= OP_DRAG_LEFT
;
378 if (m_sensitivity
& OP_DRAG_LEFT
)
379 m_sensitivity
= m_sensitivity
- OP_DRAG_LEFT
;
383 wxNode
*node
= m_children
.First();
386 wxShape
*obj
= (wxShape
*)node
->Data();
387 obj
->SetDraggable(drag
, TRUE
);
393 void wxShape::SetDrawHandles(bool drawH
)
395 m_drawHandles
= drawH
;
396 wxNode
*node
= m_children
.First();
399 wxShape
*obj
= (wxShape
*)node
->Data();
400 obj
->SetDrawHandles(drawH
);
405 void wxShape::SetShadowMode(int mode
, bool redraw
)
407 if (redraw
&& GetCanvas())
409 wxClientDC
dc(GetCanvas());
410 GetCanvas()->PrepareDC(dc
);
423 void wxShape::SetCanvas(wxShapeCanvas
*theCanvas
)
425 m_canvas
= theCanvas
;
426 wxNode
*node
= m_children
.First();
429 wxShape
*child
= (wxShape
*)node
->Data();
430 child
->SetCanvas(theCanvas
);
435 void wxShape::AddToCanvas(wxShapeCanvas
*theCanvas
, wxShape
*addAfter
)
437 theCanvas
->AddShape(this, addAfter
);
438 wxNode
*node
= m_children
.First();
439 wxShape
*lastImage
= this;
442 wxShape
*object
= (wxShape
*)node
->Data();
443 object
->AddToCanvas(theCanvas
, lastImage
);
450 // Insert at front of canvas
451 void wxShape::InsertInCanvas(wxShapeCanvas
*theCanvas
)
453 theCanvas
->InsertShape(this);
454 wxNode
*node
= m_children
.First();
455 wxShape
*lastImage
= this;
458 wxShape
*object
= (wxShape
*)node
->Data();
459 object
->AddToCanvas(theCanvas
, lastImage
);
466 void wxShape::RemoveFromCanvas(wxShapeCanvas
*theCanvas
)
470 theCanvas
->RemoveShape(this);
471 wxNode
*node
= m_children
.First();
474 wxShape
*object
= (wxShape
*)node
->Data();
475 object
->RemoveFromCanvas(theCanvas
);
481 void wxShape::ClearAttachments()
483 wxNode
*node
= m_attachmentPoints
.First();
486 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
490 m_attachmentPoints
.Clear();
493 void wxShape::ClearText(int regionId
)
497 m_text
.DeleteContents(TRUE
);
499 m_text
.DeleteContents(FALSE
);
501 wxNode
*node
= m_regions
.Nth(regionId
);
504 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
508 void wxShape::ClearRegions()
510 wxNode
*node
= m_regions
.First();
513 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
514 wxNode
*next
= node
->Next();
521 void wxShape::AddRegion(wxShapeRegion
*region
)
523 m_regions
.Append(region
);
526 void wxShape::SetDefaultRegionSize()
528 wxNode
*node
= m_regions
.First();
530 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
532 GetBoundingBoxMin(&w
, &h
);
533 region
->SetSize(w
, h
);
536 bool wxShape::HitTest(double x
, double y
, int *attachment
, double *distance
)
541 double width
= 0.0, height
= 0.0;
542 GetBoundingBoxMin(&width
, &height
);
543 if (fabs(width
) < 4.0) width
= 4.0;
544 if (fabs(height
) < 4.0) height
= 4.0;
546 width
+= (double)4.0; height
+= (double)4.0; // Allowance for inaccurate mousing
548 double left
= (double)(m_xpos
- (width
/2.0));
549 double top
= (double)(m_ypos
- (height
/2.0));
550 double right
= (double)(m_xpos
+ (width
/2.0));
551 double bottom
= (double)(m_ypos
+ (height
/2.0));
553 int nearest_attachment
= 0;
555 // If within the bounding box, check the attachment points
556 // within the object.
558 if (x
>= left
&& x
<= right
&& y
>= top
&& y
<= bottom
)
560 int n
= GetNumberOfAttachments();
561 double nearest
= 999999.0;
563 // GetAttachmentPosition[Edge] takes a logical attachment position,
564 // i.e. if it's rotated through 90%, position 0 is East-facing.
566 for (int i
= 0; i
< n
; i
++)
569 if (GetAttachmentPositionEdge(i
, &xp
, &yp
))
571 double l
= (double)sqrt(((xp
- x
) * (xp
- x
)) +
572 ((yp
- y
) * (yp
- y
)));
577 nearest_attachment
= i
;
581 *attachment
= nearest_attachment
;
588 // Format a text string according to the region size, adding
589 // strings with positions to region text list
591 static bool GraphicsInSizeToContents
= FALSE
; // Infinite recursion elimination
592 void wxShape::FormatText(wxDC
& dc
, const wxString
& s
, int i
)
597 if (m_regions
.Number() < 1)
599 wxNode
*node
= m_regions
.Nth(i
);
603 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
605 dc
.SetFont(* region
->GetFont());
607 region
->GetSize(&w
, &h
);
609 wxStringList
*stringList
= oglFormatText(dc
, s
, (w
-5), (h
-5), region
->GetFormatMode());
610 node
= stringList
->First();
613 wxChar
*s
= (wxChar
*)node
->Data();
614 wxShapeTextLine
*line
= new wxShapeTextLine(0.0, 0.0, s
);
615 region
->GetFormattedText().Append((wxObject
*)line
);
621 // Don't try to resize an object with more than one image (this case should be dealt
622 // with by overriden handlers)
623 if ((region
->GetFormatMode() & FORMAT_SIZE_TO_CONTENTS
) &&
624 (region
->GetFormattedText().Number() > 0) &&
625 (m_regions
.Number() == 1) && !GraphicsInSizeToContents
)
627 oglGetCentredTextExtent(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, w
, h
, &actualW
, &actualH
);
628 if ((actualW
+m_textMarginX
!= w
) || (actualH
+m_textMarginY
!= h
))
630 // If we are a descendant of a composite, must make sure the composite gets
632 wxShape
*topAncestor
= GetTopAncestor();
634 if (topAncestor
!= this)
636 // Make sure we don't recurse infinitely
637 GraphicsInSizeToContents
= TRUE
;
639 wxCompositeShape
*composite
= (wxCompositeShape
*)topAncestor
;
640 composite
->Erase(dc
);
641 SetSize(actualW
+m_textMarginX
, actualH
+m_textMarginY
);
642 Move(dc
, m_xpos
, m_ypos
);
643 composite
->CalculateSize();
644 if (composite
->Selected())
646 composite
->DeleteControlPoints(& dc
);
647 composite
->MakeControlPoints();
648 composite
->MakeMandatoryControlPoints();
650 // Where infinite recursion might happen if we didn't stop it
653 GraphicsInSizeToContents
= FALSE
;
658 SetSize(actualW
+m_textMarginX
, actualH
+m_textMarginY
);
659 Move(dc
, m_xpos
, m_ypos
);
661 SetSize(actualW
+m_textMarginX
, actualH
+m_textMarginY
);
662 Move(dc
, m_xpos
, m_ypos
);
666 oglCentreText(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, actualW
, actualH
, region
->GetFormatMode());
670 void wxShape::Recentre(wxDC
& dc
)
673 GetBoundingBoxMin(&w
, &h
);
675 int noRegions
= m_regions
.Number();
676 for (int i
= 0; i
< noRegions
; i
++)
678 wxNode
*node
= m_regions
.Nth(i
);
681 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
682 oglCentreText(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, w
, h
, region
->GetFormatMode());
687 bool wxShape::GetPerimeterPoint(double x1
, double y1
,
688 double x2
, double y2
,
689 double *x3
, double *y3
)
694 void wxShape::SetPen(wxPen
*the_pen
)
699 void wxShape::SetBrush(wxBrush
*the_brush
)
704 // Get the top-most (non-division) ancestor, or self
705 wxShape
*wxShape::GetTopAncestor()
710 if (GetParent()->IsKindOf(CLASSINFO(wxDivisionShape
)))
712 else return GetParent()->GetTopAncestor();
719 void wxShape::SetFont(wxFont
*the_font
, int regionId
)
722 wxNode
*node
= m_regions
.Nth(regionId
);
725 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
726 region
->SetFont(the_font
);
729 wxFont
*wxShape::GetFont(int n
) const
731 wxNode
*node
= m_regions
.Nth(n
);
734 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
735 return region
->GetFont();
738 void wxShape::SetFormatMode(int mode
, int regionId
)
740 wxNode
*node
= m_regions
.Nth(regionId
);
743 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
744 region
->SetFormatMode(mode
);
747 int wxShape::GetFormatMode(int regionId
) const
749 wxNode
*node
= m_regions
.Nth(regionId
);
752 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
753 return region
->GetFormatMode();
756 void wxShape::SetTextColour(const wxString
& the_colour
, int regionId
)
758 wxColour
*wxcolour
= wxTheColourDatabase
->FindColour(the_colour
);
759 m_textColour
= wxcolour
;
760 m_textColourName
= the_colour
;
762 wxNode
*node
= m_regions
.Nth(regionId
);
765 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
766 region
->SetColour(the_colour
);
769 wxString
wxShape::GetTextColour(int regionId
) const
771 wxNode
*node
= m_regions
.Nth(regionId
);
773 return wxEmptyString
;
774 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
775 return region
->GetColour();
778 void wxShape::SetRegionName(const wxString
& name
, int regionId
)
780 wxNode
*node
= m_regions
.Nth(regionId
);
783 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
784 region
->SetName(name
);
787 wxString
wxShape::GetRegionName(int regionId
)
789 wxNode
*node
= m_regions
.Nth(regionId
);
791 return wxEmptyString
;
792 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
793 return region
->GetName();
796 int wxShape::GetRegionId(const wxString
& name
)
798 wxNode
*node
= m_regions
.First();
802 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
803 if (region
->GetName() == name
)
811 // Name all m_regions in all subimages recursively.
812 void wxShape::NameRegions(const wxString
& parentName
)
814 int n
= GetNumberOfTextRegions();
816 for (int i
= 0; i
< n
; i
++)
818 if (parentName
.Length() > 0)
819 buff
<< parentName
<< wxT(".") << i
;
822 SetRegionName(buff
, i
);
824 wxNode
*node
= m_children
.First();
829 wxShape
*child
= (wxShape
*)node
->Data();
830 if (parentName
.Length() > 0)
831 buff
<< parentName
<< wxT(".") << j
;
834 child
->NameRegions(buff
);
840 // Get a region by name, possibly looking recursively into composites.
841 wxShape
*wxShape::FindRegion(const wxString
& name
, int *regionId
)
843 int id
= GetRegionId(name
);
850 wxNode
*node
= m_children
.First();
853 wxShape
*child
= (wxShape
*)node
->Data();
854 wxShape
*actualImage
= child
->FindRegion(name
, regionId
);
862 // Finds all region names for this image (composite or simple).
863 // Supply empty string list.
864 void wxShape::FindRegionNames(wxStringList
& list
)
866 int n
= GetNumberOfTextRegions();
867 for (int i
= 0; i
< n
; i
++)
869 wxString
name(GetRegionName(i
));
873 wxNode
*node
= m_children
.First();
876 wxShape
*child
= (wxShape
*)node
->Data();
877 child
->FindRegionNames(list
);
882 void wxShape::AssignNewIds()
886 wxNode
*node
= m_children
.First();
889 wxShape
*child
= (wxShape
*)node
->Data();
890 child
->AssignNewIds();
895 void wxShape::OnDraw(wxDC
& dc
)
899 void wxShape::OnMoveLinks(wxDC
& dc
)
901 // Want to set the ends of all attached links
902 // to point to/from this object
904 wxNode
*current
= m_lines
.First();
907 wxLineShape
*line
= (wxLineShape
*)current
->Data();
908 line
->GetEventHandler()->OnMoveLink(dc
);
909 current
= current
->Next();
914 void wxShape::OnDrawContents(wxDC
& dc
)
916 double bound_x
, bound_y
;
917 GetBoundingBoxMin(&bound_x
, &bound_y
);
918 if (m_regions
.Number() < 1) return;
920 if (m_pen
) dc
.SetPen(* m_pen
);
922 wxShapeRegion
*region
= (wxShapeRegion
*)m_regions
.First()->Data();
923 if (region
->GetFont()) dc
.SetFont(* region
->GetFont());
925 dc
.SetTextForeground(* (region
->GetActualColourObject()));
926 dc
.SetBackgroundMode(wxTRANSPARENT
);
929 oglCentreText(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, bound_x
, bound_y
, region
->GetFormatMode());
932 if (!GetDisableLabel())
934 oglDrawFormattedText(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, bound_x
, bound_y
, region
->GetFormatMode());
938 void wxShape::DrawContents(wxDC
& dc
)
940 GetEventHandler()->OnDrawContents(dc
);
943 void wxShape::OnSize(double x
, double y
)
947 bool wxShape::OnMovePre(wxDC
& dc
, double x
, double y
, double old_x
, double old_y
, bool display
)
952 void wxShape::OnMovePost(wxDC
& dc
, double x
, double y
, double old_x
, double old_y
, bool display
)
956 void wxShape::OnErase(wxDC
& dc
)
962 wxNode
*current
= m_lines
.First();
965 wxLineShape
*line
= (wxLineShape
*)current
->Data();
966 line
->GetEventHandler()->OnErase(dc
);
967 current
= current
->Next();
969 GetEventHandler()->OnEraseContents(dc
);
972 void wxShape::OnEraseContents(wxDC
& dc
)
977 double maxX
, maxY
, minX
, minY
;
980 GetBoundingBoxMin(&minX
, &minY
);
981 GetBoundingBoxMax(&maxX
, &maxY
);
982 double topLeftX
= (double)(xp
- (maxX
/ 2.0) - 2.0);
983 double topLeftY
= (double)(yp
- (maxY
/ 2.0) - 2.0);
987 penWidth
= m_pen
->GetWidth();
989 dc
.SetPen(GetBackgroundPen());
990 dc
.SetBrush(GetBackgroundBrush());
992 dc
.DrawRectangle(WXROUND(topLeftX
- penWidth
), WXROUND(topLeftY
- penWidth
),
993 WXROUND(maxX
+ penWidth
*2.0 + 4.0), WXROUND(maxY
+ penWidth
*2.0 + 4.0));
996 void wxShape::EraseLinks(wxDC
& dc
, int attachment
, bool recurse
)
1001 wxNode
*current
= m_lines
.First();
1004 wxLineShape
*line
= (wxLineShape
*)current
->Data();
1005 if (attachment
== -1 || ((line
->GetTo() == this && line
->GetAttachmentTo() == attachment
) ||
1006 (line
->GetFrom() == this && line
->GetAttachmentFrom() == attachment
)))
1007 line
->GetEventHandler()->OnErase(dc
);
1008 current
= current
->Next();
1012 wxNode
*node
= m_children
.First();
1015 wxShape
*child
= (wxShape
*)node
->Data();
1016 child
->EraseLinks(dc
, attachment
, recurse
);
1017 node
= node
->Next();
1022 void wxShape::DrawLinks(wxDC
& dc
, int attachment
, bool recurse
)
1027 wxNode
*current
= m_lines
.First();
1030 wxLineShape
*line
= (wxLineShape
*)current
->Data();
1031 if (attachment
== -1 ||
1032 (line
->GetTo() == this && line
->GetAttachmentTo() == attachment
) ||
1033 (line
->GetFrom() == this && line
->GetAttachmentFrom() == attachment
))
1035 current
= current
->Next();
1039 wxNode
*node
= m_children
.First();
1042 wxShape
*child
= (wxShape
*)node
->Data();
1043 child
->DrawLinks(dc
, attachment
, recurse
);
1044 node
= node
->Next();
1049 // Returns TRUE if pt1 <= pt2 in the sense that one point comes before another on an
1050 // edge of the shape.
1051 // attachmentPoint is the attachment point (= side) in question.
1053 // This is the default, rectangular implementation.
1054 bool wxShape::AttachmentSortTest(int attachmentPoint
, const wxRealPoint
& pt1
, const wxRealPoint
& pt2
)
1056 int physicalAttachment
= LogicalToPhysicalAttachment(attachmentPoint
);
1057 switch (physicalAttachment
)
1062 return (pt1
.x
<= pt2
.x
) ;
1068 return (pt1
.y
<= pt2
.y
) ;
1076 bool wxShape::MoveLineToNewAttachment(wxDC
& dc
, wxLineShape
*to_move
,
1079 if (GetAttachmentMode() == ATTACHMENT_MODE_NONE
)
1082 int newAttachment
, oldAttachment
;
1085 // Is (x, y) on this object? If so, find the new attachment point
1086 // the user has moved the point to
1087 bool hit
= HitTest(x
, y
, &newAttachment
, &distance
);
1093 if (to_move
->GetTo() == this)
1094 oldAttachment
= to_move
->GetAttachmentTo();
1096 oldAttachment
= to_move
->GetAttachmentFrom();
1098 // The links in a new ordering.
1101 // First, add all links to the new list.
1102 wxNode
*node
= m_lines
.First();
1105 newOrdering
.Append(node
->Data());
1106 node
= node
->Next();
1109 // Delete the line object from the list of links; we're going to move
1110 // it to another position in the list
1111 newOrdering
.DeleteObject(to_move
);
1113 double old_x
= (double) -99999.9;
1114 double old_y
= (double) -99999.9;
1116 node
= newOrdering
.First();
1119 while (!found
&& node
)
1121 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1122 if ((line
->GetTo() == this && oldAttachment
== line
->GetAttachmentTo()) ||
1123 (line
->GetFrom() == this && oldAttachment
== line
->GetAttachmentFrom()))
1125 double startX
, startY
, endX
, endY
;
1127 line
->GetEnds(&startX
, &startY
, &endX
, &endY
);
1128 if (line
->GetTo() == this)
1138 wxRealPoint
thisPoint(xp
, yp
);
1139 wxRealPoint
lastPoint(old_x
, old_y
);
1140 wxRealPoint
newPoint(x
, y
);
1142 if (AttachmentSortTest(newAttachment
, newPoint
, thisPoint
) && AttachmentSortTest(newAttachment
, lastPoint
, newPoint
))
1145 newOrdering
.Insert(node
, to_move
);
1151 node
= node
->Next();
1155 newOrdering
.Append(to_move
);
1157 GetEventHandler()->OnChangeAttachment(newAttachment
, to_move
, newOrdering
);
1162 void wxShape::OnChangeAttachment(int attachment
, wxLineShape
* line
, wxList
& ordering
)
1164 if (line
->GetTo() == this)
1165 line
->SetAttachmentTo(attachment
);
1167 line
->SetAttachmentFrom(attachment
);
1169 ApplyAttachmentOrdering(ordering
);
1171 wxClientDC
dc(GetCanvas());
1172 GetCanvas()->PrepareDC(dc
);
1176 if (!GetCanvas()->GetQuickEditMode()) GetCanvas()->Redraw(dc
);
1179 // Reorders the lines according to the given list.
1180 void wxShape::ApplyAttachmentOrdering(wxList
& linesToSort
)
1182 // This is a temporary store of all the lines.
1185 wxNode
*node
= m_lines
.First();
1188 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1189 linesStore
.Append(line
);
1190 node
= node
->Next();;
1195 node
= linesToSort
.First();
1198 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1199 if (linesStore
.Member(line
))
1202 linesStore
.DeleteObject(line
);
1203 m_lines
.Append(line
);
1205 node
= node
->Next();
1208 // Now add any lines that haven't been listed in linesToSort.
1209 node
= linesStore
.First();
1212 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1213 m_lines
.Append(line
);
1214 node
= node
->Next();
1218 // Reorders the lines coming into the node image at this attachment
1219 // position, in the order in which they appear in linesToSort.
1220 // Any remaining lines not in the list will be added to the end.
1221 void wxShape::SortLines(int attachment
, wxList
& linesToSort
)
1223 // This is a temporary store of all the lines at this attachment
1224 // point. We'll tick them off as we've processed them.
1225 wxList linesAtThisAttachment
;
1227 wxNode
*node
= m_lines
.First();
1230 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1231 wxNode
*next
= node
->Next();
1232 if ((line
->GetTo() == this && line
->GetAttachmentTo() == attachment
) ||
1233 (line
->GetFrom() == this && line
->GetAttachmentFrom() == attachment
))
1235 linesAtThisAttachment
.Append(line
);
1239 else node
= node
->Next();
1242 node
= linesToSort
.First();
1245 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1246 if (linesAtThisAttachment
.Member(line
))
1249 linesAtThisAttachment
.DeleteObject(line
);
1250 m_lines
.Append(line
);
1252 node
= node
->Next();
1255 // Now add any lines that haven't been listed in linesToSort.
1256 node
= linesAtThisAttachment
.First();
1259 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1260 m_lines
.Append(line
);
1261 node
= node
->Next();
1265 void wxShape::OnHighlight(wxDC
& dc
)
1269 void wxShape::OnLeftClick(double x
, double y
, int keys
, int attachment
)
1271 if ((m_sensitivity
& OP_CLICK_LEFT
) != OP_CLICK_LEFT
)
1277 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1278 m_parent
->GetEventHandler()->OnLeftClick(x
, y
, keys
, attachment
);
1284 void wxShape::OnRightClick(double x
, double y
, int keys
, int attachment
)
1286 if ((m_sensitivity
& OP_CLICK_RIGHT
) != OP_CLICK_RIGHT
)
1292 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1293 m_parent
->GetEventHandler()->OnRightClick(x
, y
, keys
, attachment
);
1299 double DragOffsetX
= 0.0;
1300 double DragOffsetY
= 0.0;
1302 void wxShape::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
1304 if ((m_sensitivity
& OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
1310 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1311 m_parent
->GetEventHandler()->OnDragLeft(draw
, x
, y
, keys
, attachment
);
1316 wxClientDC
dc(GetCanvas());
1317 GetCanvas()->PrepareDC(dc
);
1319 dc
.SetLogicalFunction(OGLRBLF
);
1321 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1322 dc
.SetPen(dottedPen
);
1323 dc
.SetBrush(* wxTRANSPARENT_BRUSH
);
1326 xx
= x
+ DragOffsetX
;
1327 yy
= y
+ DragOffsetY
;
1329 m_canvas
->Snap(&xx
, &yy
);
1330 // m_xpos = xx; m_ypos = yy;
1332 GetBoundingBoxMax(&w
, &h
);
1333 GetEventHandler()->OnDrawOutline(dc
, xx
, yy
, w
, h
);
1336 void wxShape::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
1338 if ((m_sensitivity
& OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
1344 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1345 m_parent
->GetEventHandler()->OnBeginDragLeft(x
, y
, keys
, attachment
);
1350 DragOffsetX
= m_xpos
- x
;
1351 DragOffsetY
= m_ypos
- y
;
1353 wxClientDC
dc(GetCanvas());
1354 GetCanvas()->PrepareDC(dc
);
1356 // New policy: don't erase shape until end of drag.
1360 xx
= x
+ DragOffsetX
;
1361 yy
= y
+ DragOffsetY
;
1362 m_canvas
->Snap(&xx
, &yy
);
1363 // m_xpos = xx; m_ypos = yy;
1364 dc
.SetLogicalFunction(OGLRBLF
);
1366 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1367 dc
.SetPen(dottedPen
);
1368 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1371 GetBoundingBoxMax(&w
, &h
);
1372 GetEventHandler()->OnDrawOutline(dc
, xx
, yy
, w
, h
);
1373 m_canvas
->CaptureMouse();
1376 void wxShape::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
1378 m_canvas
->ReleaseMouse();
1379 if ((m_sensitivity
& OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
1385 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1386 m_parent
->GetEventHandler()->OnEndDragLeft(x
, y
, keys
, attachment
);
1391 wxClientDC
dc(GetCanvas());
1392 GetCanvas()->PrepareDC(dc
);
1394 dc
.SetLogicalFunction(wxCOPY
);
1396 double xx
= x
+ DragOffsetX
;
1397 double yy
= y
+ DragOffsetY
;
1398 m_canvas
->Snap(&xx
, &yy
);
1399 // canvas->Snap(&m_xpos, &m_ypos);
1401 // New policy: erase shape at end of drag.
1405 if (m_canvas
&& !m_canvas
->GetQuickEditMode()) m_canvas
->Redraw(dc
);
1408 void wxShape::OnDragRight(bool draw
, double x
, double y
, int keys
, int attachment
)
1410 if ((m_sensitivity
& OP_DRAG_RIGHT
) != OP_DRAG_RIGHT
)
1416 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1417 m_parent
->GetEventHandler()->OnDragRight(draw
, x
, y
, keys
, attachment
);
1423 void wxShape::OnBeginDragRight(double x
, double y
, int keys
, int attachment
)
1425 if ((m_sensitivity
& OP_DRAG_RIGHT
) != OP_DRAG_RIGHT
)
1431 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1432 m_parent
->GetEventHandler()->OnBeginDragRight(x
, y
, keys
, attachment
);
1438 void wxShape::OnEndDragRight(double x
, double y
, int keys
, int attachment
)
1440 if ((m_sensitivity
& OP_DRAG_RIGHT
) != OP_DRAG_RIGHT
)
1446 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1447 m_parent
->GetEventHandler()->OnEndDragRight(x
, y
, keys
, attachment
);
1453 void wxShape::OnDrawOutline(wxDC
& dc
, double x
, double y
, double w
, double h
)
1455 double top_left_x
= (double)(x
- w
/2.0);
1456 double top_left_y
= (double)(y
- h
/2.0);
1457 double top_right_x
= (double)(top_left_x
+ w
);
1458 double top_right_y
= (double)top_left_y
;
1459 double bottom_left_x
= (double)top_left_x
;
1460 double bottom_left_y
= (double)(top_left_y
+ h
);
1461 double bottom_right_x
= (double)top_right_x
;
1462 double bottom_right_y
= (double)bottom_left_y
;
1465 points
[0].x
= WXROUND(top_left_x
); points
[0].y
= WXROUND(top_left_y
);
1466 points
[1].x
= WXROUND(top_right_x
); points
[1].y
= WXROUND(top_right_y
);
1467 points
[2].x
= WXROUND(bottom_right_x
); points
[2].y
= WXROUND(bottom_right_y
);
1468 points
[3].x
= WXROUND(bottom_left_x
); points
[3].y
= WXROUND(bottom_left_y
);
1469 points
[4].x
= WXROUND(top_left_x
); points
[4].y
= WXROUND(top_left_y
);
1471 dc
.DrawLines(5, points
);
1474 void wxShape::Attach(wxShapeCanvas
*can
)
1479 void wxShape::Detach()
1484 void wxShape::Move(wxDC
& dc
, double x
, double y
, bool display
)
1486 double old_x
= m_xpos
;
1487 double old_y
= m_ypos
;
1489 if (!GetEventHandler()->OnMovePre(dc
, x
, y
, old_x
, old_y
, display
))
1496 m_xpos
= x
; m_ypos
= y
;
1498 ResetControlPoints();
1505 GetEventHandler()->OnMovePost(dc
, x
, y
, old_x
, old_y
, display
);
1508 void wxShape::MoveLinks(wxDC
& dc
)
1510 GetEventHandler()->OnMoveLinks(dc
);
1514 void wxShape::Draw(wxDC
& dc
)
1518 GetEventHandler()->OnDraw(dc
);
1519 GetEventHandler()->OnDrawContents(dc
);
1520 GetEventHandler()->OnDrawControlPoints(dc
);
1521 GetEventHandler()->OnDrawBranches(dc
);
1525 void wxShape::Flash()
1529 wxClientDC
dc(GetCanvas());
1530 GetCanvas()->PrepareDC(dc
);
1532 dc
.SetLogicalFunction(OGLRBLF
);
1534 dc
.SetLogicalFunction(wxCOPY
);
1539 void wxShape::Show(bool show
)
1542 wxNode
*node
= m_children
.First();
1545 wxShape
*image
= (wxShape
*)node
->Data();
1547 node
= node
->Next();
1551 void wxShape::Erase(wxDC
& dc
)
1553 GetEventHandler()->OnErase(dc
);
1554 GetEventHandler()->OnEraseControlPoints(dc
);
1555 GetEventHandler()->OnDrawBranches(dc
, TRUE
);
1558 void wxShape::EraseContents(wxDC
& dc
)
1560 GetEventHandler()->OnEraseContents(dc
);
1563 void wxShape::AddText(const wxString
& string
)
1565 wxNode
*node
= m_regions
.First();
1568 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
1569 region
->ClearText();
1570 wxShapeTextLine
*new_line
=
1571 new wxShapeTextLine(0.0, 0.0, string
);
1572 region
->GetFormattedText().Append(new_line
);
1574 m_formatted
= FALSE
;
1577 void wxShape::SetSize(double x
, double y
, bool recursive
)
1579 SetAttachmentSize(x
, y
);
1580 SetDefaultRegionSize();
1583 void wxShape::SetAttachmentSize(double w
, double h
)
1587 double width
, height
;
1588 GetBoundingBoxMin(&width
, &height
);
1591 else scaleX
= w
/width
;
1594 else scaleY
= h
/height
;
1596 wxNode
*node
= m_attachmentPoints
.First();
1599 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
1600 point
->m_x
= (double)(point
->m_x
* scaleX
);
1601 point
->m_y
= (double)(point
->m_y
* scaleY
);
1602 node
= node
->Next();
1606 // Add line FROM this object
1607 void wxShape::AddLine(wxLineShape
*line
, wxShape
*other
,
1608 int attachFrom
, int attachTo
,
1609 // The line ordering
1610 int positionFrom
, int positionTo
)
1612 if (positionFrom
== -1)
1614 if (!m_lines
.Member(line
))
1615 m_lines
.Append(line
);
1619 // Don't preserve old ordering if we have new ordering instructions
1620 m_lines
.DeleteObject(line
);
1621 if (positionFrom
< m_lines
.Number())
1623 wxNode
* node
= m_lines
.Nth(positionFrom
);
1624 m_lines
.Insert(node
, line
);
1627 m_lines
.Append(line
);
1630 if (positionTo
== -1)
1632 if (!other
->m_lines
.Member(line
))
1633 other
->m_lines
.Append(line
);
1637 // Don't preserve old ordering if we have new ordering instructions
1638 other
->m_lines
.DeleteObject(line
);
1639 if (positionTo
< other
->m_lines
.Number())
1641 wxNode
* node
= other
->m_lines
.Nth(positionTo
);
1642 other
->m_lines
.Insert(node
, line
);
1645 other
->m_lines
.Append(line
);
1648 // Wrong: doesn't preserve ordering of shape already linked
1649 m_lines
.DeleteObject(line
);
1650 other
->m_lines
.DeleteObject(line
);
1652 if (positionFrom
== -1)
1653 m_lines
.Append(line
);
1656 if (positionFrom
< m_lines
.Number())
1658 wxNode
* node
= m_lines
.Nth(positionFrom
);
1659 m_lines
.Insert(node
, line
);
1662 m_lines
.Append(line
);
1665 if (positionTo
== -1)
1666 other
->m_lines
.Append(line
);
1669 if (positionTo
< other
->m_lines
.Number())
1671 wxNode
* node
= other
->m_lines
.Nth(positionTo
);
1672 other
->m_lines
.Insert(node
, line
);
1675 other
->m_lines
.Append(line
);
1679 line
->SetFrom(this);
1681 line
->SetAttachments(attachFrom
, attachTo
);
1684 void wxShape::RemoveLine(wxLineShape
*line
)
1686 if (line
->GetFrom() == this)
1687 line
->GetTo()->m_lines
.DeleteObject(line
);
1689 line
->GetFrom()->m_lines
.DeleteObject(line
);
1691 m_lines
.DeleteObject(line
);
1695 void wxShape::WriteAttributes(wxExpr
*clause
)
1697 clause
->AddAttributeValueString("type", GetClassInfo()->GetClassName());
1698 clause
->AddAttributeValue("id", m_id
);
1702 int penWidth
= m_pen
->GetWidth();
1703 int penStyle
= m_pen
->GetStyle();
1705 clause
->AddAttributeValue("pen_width", (long)penWidth
);
1706 if (penStyle
!= wxSOLID
)
1707 clause
->AddAttributeValue("pen_style", (long)penStyle
);
1709 wxString penColour
= wxTheColourDatabase
->FindName(m_pen
->GetColour());
1710 if (penColour
== "")
1712 wxString
hex(oglColourToHex(m_pen
->GetColour()));
1713 hex
= wxString("#") + hex
;
1714 clause
->AddAttributeValueString("pen_colour", hex
);
1716 else if (penColour
!= "BLACK")
1717 clause
->AddAttributeValueString("pen_colour", penColour
);
1722 wxString brushColour
= wxTheColourDatabase
->FindName(m_brush
->GetColour());
1724 if (brushColour
== "")
1726 wxString
hex(oglColourToHex(m_brush
->GetColour()));
1727 hex
= wxString("#") + hex
;
1728 clause
->AddAttributeValueString("brush_colour", hex
);
1730 else if (brushColour
!= "WHITE")
1731 clause
->AddAttributeValueString("brush_colour", brushColour
);
1733 if (m_brush
->GetStyle() != wxSOLID
)
1734 clause
->AddAttributeValue("brush_style", (long)m_brush
->GetStyle());
1739 int n_lines
= m_lines
.Number();
1742 wxExpr
*list
= new wxExpr(wxExprList
);
1743 wxNode
*node
= m_lines
.First();
1746 wxShape
*line
= (wxShape
*)node
->Data();
1747 wxExpr
*id_expr
= new wxExpr(line
->GetId());
1748 list
->Append(id_expr
);
1749 node
= node
->Next();
1751 clause
->AddAttributeValue("arcs", list
);
1754 // Miscellaneous members
1755 if (m_attachmentMode
!= 0)
1756 clause
->AddAttributeValue("use_attachments", (long)m_attachmentMode
);
1757 if (m_sensitivity
!= OP_ALL
)
1758 clause
->AddAttributeValue("sensitivity", (long)m_sensitivity
);
1759 if (!m_spaceAttachments
)
1760 clause
->AddAttributeValue("space_attachments", (long)m_spaceAttachments
);
1762 clause
->AddAttributeValue("fixed_width", (long)m_fixedWidth
);
1764 clause
->AddAttributeValue("fixed_height", (long)m_fixedHeight
);
1765 if (m_shadowMode
!= SHADOW_NONE
)
1766 clause
->AddAttributeValue("shadow_mode", (long)m_shadowMode
);
1767 if (m_centreResize
!= TRUE
)
1768 clause
->AddAttributeValue("centre_resize", (long)0);
1769 clause
->AddAttributeValue("maintain_aspect_ratio", (long) m_maintainAspectRatio
);
1770 if (m_highlighted
!= FALSE
)
1771 clause
->AddAttributeValue("hilite", (long)m_highlighted
);
1773 if (m_parent
) // For composite objects
1774 clause
->AddAttributeValue("parent", (long)m_parent
->GetId());
1776 if (m_rotation
!= 0.0)
1777 clause
->AddAttributeValue("rotation", m_rotation
);
1779 if (!this->IsKindOf(CLASSINFO(wxLineShape
)))
1781 clause
->AddAttributeValue("neck_length", (long) m_branchNeckLength
);
1782 clause
->AddAttributeValue("stem_length", (long) m_branchStemLength
);
1783 clause
->AddAttributeValue("branch_spacing", (long) m_branchSpacing
);
1784 clause
->AddAttributeValue("branch_style", (long) m_branchStyle
);
1787 // Write user-defined attachment points, if any
1788 if (m_attachmentPoints
.Number() > 0)
1790 wxExpr
*attachmentList
= new wxExpr(wxExprList
);
1791 wxNode
*node
= m_attachmentPoints
.First();
1794 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
1795 wxExpr
*pointExpr
= new wxExpr(wxExprList
);
1796 pointExpr
->Append(new wxExpr((long)point
->m_id
));
1797 pointExpr
->Append(new wxExpr(point
->m_x
));
1798 pointExpr
->Append(new wxExpr(point
->m_y
));
1799 attachmentList
->Append(pointExpr
);
1800 node
= node
->Next();
1802 clause
->AddAttributeValue("user_attachments", attachmentList
);
1805 // Write text regions
1806 WriteRegions(clause
);
1809 void wxShape::WriteRegions(wxExpr
*clause
)
1811 // Output regions as region1 = (...), region2 = (...), etc
1812 // and formatted text as text1 = (...), text2 = (...) etc.
1814 char regionNameBuf
[20];
1815 char textNameBuf
[20];
1816 wxNode
*node
= m_regions
.First();
1819 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
1820 sprintf(regionNameBuf
, "region%d", regionNo
);
1821 sprintf(textNameBuf
, "text%d", regionNo
);
1823 // Original text and region attributes:
1824 // region1 = (regionName regionText x y width height minWidth minHeight proportionX proportionY
1825 // formatMode fontSize fontFamily fontStyle fontWeight textColour)
1826 wxExpr
*regionExpr
= new wxExpr(wxExprList
);
1827 regionExpr
->Append(new wxExpr(wxExprString
, region
->m_regionName
));
1828 regionExpr
->Append(new wxExpr(wxExprString
, region
->m_regionText
));
1830 regionExpr
->Append(new wxExpr(region
->m_x
));
1831 regionExpr
->Append(new wxExpr(region
->m_y
));
1832 regionExpr
->Append(new wxExpr(region
->GetWidth()));
1833 regionExpr
->Append(new wxExpr(region
->GetHeight()));
1835 regionExpr
->Append(new wxExpr(region
->m_minWidth
));
1836 regionExpr
->Append(new wxExpr(region
->m_minHeight
));
1837 regionExpr
->Append(new wxExpr(region
->m_regionProportionX
));
1838 regionExpr
->Append(new wxExpr(region
->m_regionProportionY
));
1840 regionExpr
->Append(new wxExpr((long)region
->m_formatMode
));
1842 regionExpr
->Append(new wxExpr((long)(region
->m_font
? region
->m_font
->GetPointSize() : 10)));
1843 regionExpr
->Append(new wxExpr((long)(region
->m_font
? region
->m_font
->GetFamily() : wxDEFAULT
)));
1844 regionExpr
->Append(new wxExpr((long)(region
->m_font
? region
->m_font
->GetStyle() : wxDEFAULT
)));
1845 regionExpr
->Append(new wxExpr((long)(region
->m_font
? region
->m_font
->GetWeight() : wxNORMAL
)));
1846 regionExpr
->Append(new wxExpr(wxExprString
, region
->m_textColour
));
1848 // New members for pen colour/style
1849 regionExpr
->Append(new wxExpr(wxExprString
, region
->m_penColour
));
1850 regionExpr
->Append(new wxExpr((long)region
->m_penStyle
));
1853 // text1 = ((x y string) (x y string) ...)
1854 wxExpr
*textExpr
= new wxExpr(wxExprList
);
1856 wxNode
*textNode
= region
->m_formattedText
.First();
1859 wxShapeTextLine
*line
= (wxShapeTextLine
*)textNode
->Data();
1860 wxExpr
*list2
= new wxExpr(wxExprList
);
1861 list2
->Append(new wxExpr(line
->GetX()));
1862 list2
->Append(new wxExpr(line
->GetY()));
1863 list2
->Append(new wxExpr(wxExprString
, line
->GetText()));
1864 textExpr
->Append(list2
);
1865 textNode
= textNode
->Next();
1868 // Now add both attributes to the clause
1869 clause
->AddAttributeValue(regionNameBuf
, regionExpr
);
1870 clause
->AddAttributeValue(textNameBuf
, textExpr
);
1872 node
= node
->Next();
1877 void wxShape::ReadAttributes(wxExpr
*clause
)
1879 clause
->GetAttributeValue("id", m_id
);
1882 clause
->GetAttributeValue("x", m_xpos
);
1883 clause
->GetAttributeValue("y", m_ypos
);
1885 // Input text strings (FOR COMPATIBILITY WITH OLD FILES ONLY. SEE REGION CODE BELOW.)
1887 wxExpr
*strings
= clause
->AttributeValue("text");
1888 if (strings
&& strings
->Type() == wxExprList
)
1890 m_formatted
= TRUE
; // Assume text is formatted unless we prove otherwise
1891 wxExpr
*node
= strings
->value
.first
;
1894 wxExpr
*string_expr
= node
;
1897 wxString
the_string("");
1899 // string_expr can either be a string, or a list of
1900 // 3 elements: x, y, and string.
1901 if (string_expr
->Type() == wxExprString
)
1903 the_string
= string_expr
->StringValue();
1904 m_formatted
= FALSE
;
1906 else if (string_expr
->Type() == wxExprList
)
1908 wxExpr
*first
= string_expr
->value
.first
;
1909 wxExpr
*second
= first
? first
->next
: (wxExpr
*) NULL
;
1910 wxExpr
*third
= second
? second
->next
: (wxExpr
*) NULL
;
1912 if (first
&& second
&& third
&&
1913 (first
->Type() == wxExprReal
|| first
->Type() == wxExprInteger
) &&
1914 (second
->Type() == wxExprReal
|| second
->Type() == wxExprInteger
) &&
1915 third
->Type() == wxExprString
)
1917 if (first
->Type() == wxExprReal
)
1918 the_x
= first
->RealValue();
1919 else the_x
= (double)first
->IntegerValue();
1921 if (second
->Type() == wxExprReal
)
1922 the_y
= second
->RealValue();
1923 else the_y
= (double)second
->IntegerValue();
1925 the_string
= third
->StringValue();
1928 wxShapeTextLine
*line
=
1929 new wxShapeTextLine(the_x
, the_y
, the_string
);
1930 m_text
.Append(line
);
1936 wxString pen_string
= "";
1937 wxString brush_string
= "";
1939 int pen_style
= wxSOLID
;
1940 int brush_style
= wxSOLID
;
1941 m_attachmentMode
= ATTACHMENT_MODE_NONE
;
1943 clause
->GetAttributeValue("pen_colour", pen_string
);
1944 clause
->GetAttributeValue("text_colour", m_textColourName
);
1946 SetTextColour(m_textColourName
);
1948 clause
->GetAttributeValue("region_name", m_regionName
);
1950 clause
->GetAttributeValue("brush_colour", brush_string
);
1951 clause
->GetAttributeValue("pen_width", pen_width
);
1952 clause
->GetAttributeValue("pen_style", pen_style
);
1953 clause
->GetAttributeValue("brush_style", brush_style
);
1955 int iVal
= (int) m_attachmentMode
;
1956 clause
->GetAttributeValue("use_attachments", iVal
);
1957 m_attachmentMode
= iVal
;
1959 clause
->GetAttributeValue("sensitivity", m_sensitivity
);
1961 iVal
= (int) m_spaceAttachments
;
1962 clause
->GetAttributeValue("space_attachments", iVal
);
1963 m_spaceAttachments
= (iVal
!= 0);
1965 iVal
= (int) m_fixedWidth
;
1966 clause
->GetAttributeValue("fixed_width", iVal
);
1967 m_fixedWidth
= (iVal
!= 0);
1969 iVal
= (int) m_fixedHeight
;
1970 clause
->GetAttributeValue("fixed_height", iVal
);
1971 m_fixedHeight
= (iVal
!= 0);
1973 clause
->GetAttributeValue("format_mode", m_formatMode
);
1974 clause
->GetAttributeValue("shadow_mode", m_shadowMode
);
1976 iVal
= m_branchNeckLength
;
1977 clause
->GetAttributeValue("neck_length", iVal
);
1978 m_branchNeckLength
= iVal
;
1980 iVal
= m_branchStemLength
;
1981 clause
->GetAttributeValue("stem_length", iVal
);
1982 m_branchStemLength
= iVal
;
1984 iVal
= m_branchSpacing
;
1985 clause
->GetAttributeValue("branch_spacing", iVal
);
1986 m_branchSpacing
= iVal
;
1988 clause
->GetAttributeValue("branch_style", m_branchStyle
);
1990 iVal
= (int) m_centreResize
;
1991 clause
->GetAttributeValue("centre_resize", iVal
);
1992 m_centreResize
= (iVal
!= 0);
1994 iVal
= (int) m_maintainAspectRatio
;
1995 clause
->GetAttributeValue("maintain_aspect_ratio", iVal
);
1996 m_maintainAspectRatio
= (iVal
!= 0);
1998 iVal
= (int) m_highlighted
;
1999 clause
->GetAttributeValue("hilite", iVal
);
2000 m_highlighted
= (iVal
!= 0);
2002 clause
->GetAttributeValue("rotation", m_rotation
);
2004 if (pen_string
== "")
2005 pen_string
= "BLACK";
2006 if (brush_string
== "")
2007 brush_string
= "WHITE";
2009 if (pen_string
.GetChar(0) == '#')
2011 wxColour
col(oglHexToColour(pen_string
.After('#')));
2012 m_pen
= wxThePenList
->FindOrCreatePen(col
, pen_width
, pen_style
);
2015 m_pen
= wxThePenList
->FindOrCreatePen(pen_string
, pen_width
, pen_style
);
2018 m_pen
= wxBLACK_PEN
;
2020 if (brush_string
.GetChar(0) == '#')
2022 wxColour
col(oglHexToColour(brush_string
.After('#')));
2023 m_brush
= wxTheBrushList
->FindOrCreateBrush(col
, brush_style
);
2026 m_brush
= wxTheBrushList
->FindOrCreateBrush(brush_string
, brush_style
);
2029 m_brush
= wxWHITE_BRUSH
;
2031 int point_size
= 10;
2032 clause
->GetAttributeValue("point_size", point_size
);
2033 SetFont(oglMatchFont(point_size
));
2035 // Read user-defined attachment points, if any
2036 wxExpr
*attachmentList
= clause
->AttributeValue("user_attachments");
2039 wxExpr
*pointExpr
= attachmentList
->GetFirst();
2042 wxExpr
*idExpr
= pointExpr
->Nth(0);
2043 wxExpr
*xExpr
= pointExpr
->Nth(1);
2044 wxExpr
*yExpr
= pointExpr
->Nth(2);
2045 if (idExpr
&& xExpr
&& yExpr
)
2047 wxAttachmentPoint
*point
= new wxAttachmentPoint
;
2048 point
->m_id
= (int)idExpr
->IntegerValue();
2049 point
->m_x
= xExpr
->RealValue();
2050 point
->m_y
= yExpr
->RealValue();
2051 m_attachmentPoints
.Append((wxObject
*)point
);
2053 pointExpr
= pointExpr
->GetNext();
2057 // Read text regions
2058 ReadRegions(clause
);
2061 void wxShape::ReadRegions(wxExpr
*clause
)
2065 // region1 = (regionName regionText x y width height minWidth minHeight proportionX proportionY
2066 // formatMode fontSize fontFamily fontStyle fontWeight textColour)
2068 char regionNameBuf
[20];
2069 char textNameBuf
[20];
2071 wxExpr
*regionExpr
= NULL
;
2072 wxExpr
*textExpr
= NULL
;
2073 sprintf(regionNameBuf
, "region%d", regionNo
);
2074 sprintf(textNameBuf
, "text%d", regionNo
);
2076 m_formatted
= TRUE
; // Assume text is formatted unless we prove otherwise
2078 while ((regionExpr
= clause
->AttributeValue(regionNameBuf
)))
2081 * Get the region information
2085 wxString
regionName("");
2086 wxString
regionText("");
2090 double height
= 0.0;
2091 double minWidth
= 5.0;
2092 double minHeight
= 5.0;
2093 double m_regionProportionX
= -1.0;
2094 double m_regionProportionY
= -1.0;
2095 int formatMode
= FORMAT_NONE
;
2097 int fontFamily
= wxSWISS
;
2098 int fontStyle
= wxNORMAL
;
2099 int fontWeight
= wxNORMAL
;
2100 wxString
regionTextColour("");
2101 wxString
penColour("");
2102 int penStyle
= wxSOLID
;
2104 if (regionExpr
->Type() == wxExprList
)
2106 wxExpr
*nameExpr
= regionExpr
->Nth(0);
2107 wxExpr
*textExpr
= regionExpr
->Nth(1);
2108 wxExpr
*xExpr
= regionExpr
->Nth(2);
2109 wxExpr
*yExpr
= regionExpr
->Nth(3);
2110 wxExpr
*widthExpr
= regionExpr
->Nth(4);
2111 wxExpr
*heightExpr
= regionExpr
->Nth(5);
2112 wxExpr
*minWidthExpr
= regionExpr
->Nth(6);
2113 wxExpr
*minHeightExpr
= regionExpr
->Nth(7);
2114 wxExpr
*propXExpr
= regionExpr
->Nth(8);
2115 wxExpr
*propYExpr
= regionExpr
->Nth(9);
2116 wxExpr
*formatExpr
= regionExpr
->Nth(10);
2117 wxExpr
*sizeExpr
= regionExpr
->Nth(11);
2118 wxExpr
*familyExpr
= regionExpr
->Nth(12);
2119 wxExpr
*styleExpr
= regionExpr
->Nth(13);
2120 wxExpr
*weightExpr
= regionExpr
->Nth(14);
2121 wxExpr
*colourExpr
= regionExpr
->Nth(15);
2122 wxExpr
*penColourExpr
= regionExpr
->Nth(16);
2123 wxExpr
*penStyleExpr
= regionExpr
->Nth(17);
2125 regionName
= nameExpr
->StringValue();
2126 regionText
= textExpr
->StringValue();
2128 x
= xExpr
->RealValue();
2129 y
= yExpr
->RealValue();
2131 width
= widthExpr
->RealValue();
2132 height
= heightExpr
->RealValue();
2134 minWidth
= minWidthExpr
->RealValue();
2135 minHeight
= minHeightExpr
->RealValue();
2137 m_regionProportionX
= propXExpr
->RealValue();
2138 m_regionProportionY
= propYExpr
->RealValue();
2140 formatMode
= (int) formatExpr
->IntegerValue();
2141 fontSize
= (int)sizeExpr
->IntegerValue();
2142 fontFamily
= (int)familyExpr
->IntegerValue();
2143 fontStyle
= (int)styleExpr
->IntegerValue();
2144 fontWeight
= (int)weightExpr
->IntegerValue();
2148 regionTextColour
= colourExpr
->StringValue();
2151 regionTextColour
= "BLACK";
2154 penColour
= penColourExpr
->StringValue();
2156 penStyle
= (int)penStyleExpr
->IntegerValue();
2158 wxFont
*font
= wxTheFontList
->FindOrCreateFont(fontSize
, fontFamily
, fontStyle
, fontWeight
);
2160 wxShapeRegion
*region
= new wxShapeRegion
;
2161 region
->SetProportions(m_regionProportionX
, m_regionProportionY
);
2162 region
->SetFont(font
);
2163 region
->SetSize(width
, height
);
2164 region
->SetPosition(x
, y
);
2165 region
->SetMinSize(minWidth
, minHeight
);
2166 region
->SetFormatMode(formatMode
);
2167 region
->SetPenStyle(penStyle
);
2168 if (penColour
!= "")
2169 region
->SetPenColour(penColour
);
2171 region
->m_textColour
= regionTextColour
;
2172 region
->m_regionText
= regionText
;
2173 region
->m_regionName
= regionName
;
2175 m_regions
.Append(region
);
2178 * Get the formatted text strings
2181 textExpr
= clause
->AttributeValue(textNameBuf
);
2182 if (textExpr
&& (textExpr
->Type() == wxExprList
))
2184 wxExpr
*node
= textExpr
->value
.first
;
2187 wxExpr
*string_expr
= node
;
2190 wxString
the_string("");
2192 // string_expr can either be a string, or a list of
2193 // 3 elements: x, y, and string.
2194 if (string_expr
->Type() == wxExprString
)
2196 the_string
= string_expr
->StringValue();
2197 m_formatted
= FALSE
;
2199 else if (string_expr
->Type() == wxExprList
)
2201 wxExpr
*first
= string_expr
->value
.first
;
2202 wxExpr
*second
= first
? first
->next
: (wxExpr
*) NULL
;
2203 wxExpr
*third
= second
? second
->next
: (wxExpr
*) NULL
;
2205 if (first
&& second
&& third
&&
2206 (first
->Type() == wxExprReal
|| first
->Type() == wxExprInteger
) &&
2207 (second
->Type() == wxExprReal
|| second
->Type() == wxExprInteger
) &&
2208 third
->Type() == wxExprString
)
2210 if (first
->Type() == wxExprReal
)
2211 the_x
= first
->RealValue();
2212 else the_x
= (double)first
->IntegerValue();
2214 if (second
->Type() == wxExprReal
)
2215 the_y
= second
->RealValue();
2216 else the_y
= (double)second
->IntegerValue();
2218 the_string
= third
->StringValue();
2223 wxShapeTextLine
*line
=
2224 new wxShapeTextLine(the_x
, the_y
, the_string
);
2225 region
->m_formattedText
.Append(line
);
2232 sprintf(regionNameBuf
, "region%d", regionNo
);
2233 sprintf(textNameBuf
, "text%d", regionNo
);
2236 // Compatibility: check for no regions (old file).
2237 // Lines and divided rectangles must deal with this compatibility
2238 // theirselves. Composites _may_ not have any regions anyway.
2239 if ((m_regions
.Number() == 0) &&
2240 !this->IsKindOf(CLASSINFO(wxLineShape
)) && !this->IsKindOf(CLASSINFO(wxDividedShape
)) &&
2241 !this->IsKindOf(CLASSINFO(wxCompositeShape
)))
2243 wxShapeRegion
*newRegion
= new wxShapeRegion
;
2244 newRegion
->SetName("0");
2245 m_regions
.Append((wxObject
*)newRegion
);
2246 if (m_text
.Number() > 0)
2248 newRegion
->ClearText();
2249 wxNode
*node
= m_text
.First();
2252 wxShapeTextLine
*textLine
= (wxShapeTextLine
*)node
->Data();
2253 wxNode
*next
= node
->Next();
2254 newRegion
->GetFormattedText().Append((wxObject
*)textLine
);
2264 void wxShape::Copy(wxShape
& copy
)
2267 copy
.m_xpos
= m_xpos
;
2268 copy
.m_ypos
= m_ypos
;
2270 copy
.m_brush
= m_brush
;
2271 copy
.m_textColour
= m_textColour
;
2272 copy
.m_centreResize
= m_centreResize
;
2273 copy
.m_maintainAspectRatio
= m_maintainAspectRatio
;
2274 copy
.m_attachmentMode
= m_attachmentMode
;
2275 copy
.m_spaceAttachments
= m_spaceAttachments
;
2276 copy
.m_highlighted
= m_highlighted
;
2277 copy
.m_rotation
= m_rotation
;
2278 copy
.m_textColourName
= m_textColourName
;
2279 copy
.m_regionName
= m_regionName
;
2281 copy
.m_sensitivity
= m_sensitivity
;
2282 copy
.m_draggable
= m_draggable
;
2283 copy
.m_fixedWidth
= m_fixedWidth
;
2284 copy
.m_fixedHeight
= m_fixedHeight
;
2285 copy
.m_formatMode
= m_formatMode
;
2286 copy
.m_drawHandles
= m_drawHandles
;
2288 copy
.m_visible
= m_visible
;
2289 copy
.m_shadowMode
= m_shadowMode
;
2290 copy
.m_shadowOffsetX
= m_shadowOffsetX
;
2291 copy
.m_shadowOffsetY
= m_shadowOffsetY
;
2292 copy
.m_shadowBrush
= m_shadowBrush
;
2294 copy
.m_branchNeckLength
= m_branchNeckLength
;
2295 copy
.m_branchStemLength
= m_branchStemLength
;
2296 copy
.m_branchSpacing
= m_branchSpacing
;
2298 // Copy text regions
2299 copy
.ClearRegions();
2300 wxNode
*node
= m_regions
.First();
2303 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
2304 wxShapeRegion
*newRegion
= new wxShapeRegion(*region
);
2305 copy
.m_regions
.Append(newRegion
);
2306 node
= node
->Next();
2310 copy
.ClearAttachments();
2311 node
= m_attachmentPoints
.First();
2314 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
2315 wxAttachmentPoint
*newPoint
= new wxAttachmentPoint
;
2316 newPoint
->m_id
= point
->m_id
;
2317 newPoint
->m_x
= point
->m_x
;
2318 newPoint
->m_y
= point
->m_y
;
2319 copy
.m_attachmentPoints
.Append((wxObject
*)newPoint
);
2320 node
= node
->Next();
2324 copy
.m_lines
.Clear();
2325 node
= m_lines
.First();
2328 wxLineShape
* line
= (wxLineShape
*) node
->Data();
2329 copy
.m_lines
.Append(line
);
2330 node
= node
->Next();
2334 // Create and return a new, fully copied object.
2335 wxShape
*wxShape::CreateNewCopy(bool resetMapping
, bool recompute
)
2338 oglObjectCopyMapping
.Clear();
2340 wxShape
* newObject
= (wxShape
*) GetClassInfo()->CreateObject();
2342 wxASSERT( (newObject
!= NULL
) );
2343 wxASSERT( (newObject
->IsKindOf(CLASSINFO(wxShape
))) );
2347 if (GetEventHandler() != this)
2349 wxShapeEvtHandler
* newHandler
= GetEventHandler()->CreateNewCopy();
2350 newObject
->SetEventHandler(newHandler
);
2351 newObject
->SetPreviousHandler(NULL
);
2352 newHandler
->SetPreviousHandler(newObject
);
2353 newHandler
->SetShape(newObject
);
2357 newObject
->Recompute();
2361 // Does the copying for this object, including copying event
2362 // handler data if any. Calls the virtual Copy function.
2363 void wxShape::CopyWithHandler(wxShape
& copy
)
2367 if (GetEventHandler() != this)
2369 wxASSERT( copy
.GetEventHandler() != NULL
);
2370 wxASSERT( copy
.GetEventHandler() != (©
) );
2371 wxASSERT( GetEventHandler()->GetClassInfo() == copy
.GetEventHandler()->GetClassInfo() );
2372 GetEventHandler()->CopyData(* (copy
.GetEventHandler()));
2377 // Default - make 6 control points
2378 void wxShape::MakeControlPoints()
2380 double maxX
, maxY
, minX
, minY
;
2382 GetBoundingBoxMax(&maxX
, &maxY
);
2383 GetBoundingBoxMin(&minX
, &minY
);
2385 double widthMin
= (double)(minX
+ CONTROL_POINT_SIZE
+ 2);
2386 double heightMin
= (double)(minY
+ CONTROL_POINT_SIZE
+ 2);
2388 // Offsets from main object
2389 double top
= (double)(- (heightMin
/ 2.0));
2390 double bottom
= (double)(heightMin
/ 2.0 + (maxY
- minY
));
2391 double left
= (double)(- (widthMin
/ 2.0));
2392 double right
= (double)(widthMin
/ 2.0 + (maxX
- minX
));
2394 wxControlPoint
*control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, left
, top
,
2395 CONTROL_POINT_DIAGONAL
);
2396 m_canvas
->AddShape(control
);
2397 m_controlPoints
.Append(control
);
2399 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, 0, top
,
2400 CONTROL_POINT_VERTICAL
);
2401 m_canvas
->AddShape(control
);
2402 m_controlPoints
.Append(control
);
2404 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, right
, 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
, right
, 0,
2410 CONTROL_POINT_HORIZONTAL
);
2411 m_canvas
->AddShape(control
);
2412 m_controlPoints
.Append(control
);
2414 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, right
, bottom
,
2415 CONTROL_POINT_DIAGONAL
);
2416 m_canvas
->AddShape(control
);
2417 m_controlPoints
.Append(control
);
2419 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, 0, bottom
,
2420 CONTROL_POINT_VERTICAL
);
2421 m_canvas
->AddShape(control
);
2422 m_controlPoints
.Append(control
);
2424 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, left
, 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
, left
, 0,
2430 CONTROL_POINT_HORIZONTAL
);
2431 m_canvas
->AddShape(control
);
2432 m_controlPoints
.Append(control
);
2436 void wxShape::MakeMandatoryControlPoints()
2438 wxNode
*node
= m_children
.First();
2441 wxShape
*child
= (wxShape
*)node
->Data();
2442 child
->MakeMandatoryControlPoints();
2443 node
= node
->Next();
2447 void wxShape::ResetMandatoryControlPoints()
2449 wxNode
*node
= m_children
.First();
2452 wxShape
*child
= (wxShape
*)node
->Data();
2453 child
->ResetMandatoryControlPoints();
2454 node
= node
->Next();
2458 void wxShape::ResetControlPoints()
2460 ResetMandatoryControlPoints();
2462 if (m_controlPoints
.Number() < 1)
2465 double maxX
, maxY
, minX
, minY
;
2467 GetBoundingBoxMax(&maxX
, &maxY
);
2468 GetBoundingBoxMin(&minX
, &minY
);
2470 double widthMin
= (double)(minX
+ CONTROL_POINT_SIZE
+ 2);
2471 double heightMin
= (double)(minY
+ CONTROL_POINT_SIZE
+ 2);
2473 // Offsets from main object
2474 double top
= (double)(- (heightMin
/ 2.0));
2475 double bottom
= (double)(heightMin
/ 2.0 + (maxY
- minY
));
2476 double left
= (double)(- (widthMin
/ 2.0));
2477 double right
= (double)(widthMin
/ 2.0 + (maxX
- minX
));
2479 wxNode
*node
= m_controlPoints
.First();
2480 wxControlPoint
*control
= (wxControlPoint
*)node
->Data();
2481 control
->m_xoffset
= left
; control
->m_yoffset
= top
;
2483 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2484 control
->m_xoffset
= 0; control
->m_yoffset
= top
;
2486 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2487 control
->m_xoffset
= right
; control
->m_yoffset
= top
;
2489 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2490 control
->m_xoffset
= right
; control
->m_yoffset
= 0;
2492 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2493 control
->m_xoffset
= right
; control
->m_yoffset
= bottom
;
2495 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2496 control
->m_xoffset
= 0; control
->m_yoffset
= bottom
;
2498 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2499 control
->m_xoffset
= left
; control
->m_yoffset
= bottom
;
2501 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2502 control
->m_xoffset
= left
; control
->m_yoffset
= 0;
2505 void wxShape::DeleteControlPoints(wxDC
*dc
)
2507 wxNode
*node
= m_controlPoints
.First();
2510 wxControlPoint
*control
= (wxControlPoint
*)node
->Data();
2512 control
->GetEventHandler()->OnErase(*dc
);
2513 m_canvas
->RemoveShape(control
);
2516 node
= m_controlPoints
.First();
2518 // Children of divisions are contained objects,
2520 if (!IsKindOf(CLASSINFO(wxDivisionShape
)))
2522 node
= m_children
.First();
2525 wxShape
*child
= (wxShape
*)node
->Data();
2526 child
->DeleteControlPoints(dc
);
2527 node
= node
->Next();
2532 void wxShape::OnDrawControlPoints(wxDC
& dc
)
2537 dc
.SetBrush(* wxBLACK_BRUSH
);
2538 dc
.SetPen(* wxBLACK_PEN
);
2540 wxNode
*node
= m_controlPoints
.First();
2543 wxControlPoint
*control
= (wxControlPoint
*)node
->Data();
2545 node
= node
->Next();
2547 // Children of divisions are contained objects,
2549 // This test bypasses the type facility for speed
2550 // (critical when drawing)
2551 if (!IsKindOf(CLASSINFO(wxDivisionShape
)))
2553 node
= m_children
.First();
2556 wxShape
*child
= (wxShape
*)node
->Data();
2557 child
->GetEventHandler()->OnDrawControlPoints(dc
);
2558 node
= node
->Next();
2563 void wxShape::OnEraseControlPoints(wxDC
& dc
)
2565 wxNode
*node
= m_controlPoints
.First();
2568 wxControlPoint
*control
= (wxControlPoint
*)node
->Data();
2570 node
= node
->Next();
2572 if (!IsKindOf(CLASSINFO(wxDivisionShape
)))
2574 node
= m_children
.First();
2577 wxShape
*child
= (wxShape
*)node
->Data();
2578 child
->GetEventHandler()->OnEraseControlPoints(dc
);
2579 node
= node
->Next();
2584 void wxShape::Select(bool select
, wxDC
* dc
)
2586 m_selected
= select
;
2589 MakeControlPoints();
2590 // Children of divisions are contained objects,
2592 if (!IsKindOf(CLASSINFO(wxDivisionShape
)))
2594 wxNode
*node
= m_children
.First();
2597 wxShape
*child
= (wxShape
*)node
->Data();
2598 child
->MakeMandatoryControlPoints();
2599 node
= node
->Next();
2603 GetEventHandler()->OnDrawControlPoints(*dc
);
2607 DeleteControlPoints(dc
);
2608 if (!IsKindOf(CLASSINFO(wxDivisionShape
)))
2610 wxNode
*node
= m_children
.First();
2613 wxShape
*child
= (wxShape
*)node
->Data();
2614 child
->DeleteControlPoints(dc
);
2615 node
= node
->Next();
2621 bool wxShape::Selected() const
2626 bool wxShape::AncestorSelected() const
2628 if (m_selected
) return TRUE
;
2632 return GetParent()->AncestorSelected();
2635 int wxShape::GetNumberOfAttachments() const
2637 // Should return the MAXIMUM attachment point id here,
2638 // so higher-level functions can iterate through all attachments,
2639 // even if they're not contiguous.
2640 if (m_attachmentPoints
.Number() == 0)
2645 wxNode
*node
= m_attachmentPoints
.First();
2648 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
2649 if (point
->m_id
> maxN
)
2651 node
= node
->Next();
2657 bool wxShape::AttachmentIsValid(int attachment
) const
2659 if (m_attachmentPoints
.Number() == 0)
2661 return ((attachment
>= 0) && (attachment
< 4)) ;
2664 wxNode
*node
= m_attachmentPoints
.First();
2667 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
2668 if (point
->m_id
== attachment
)
2670 node
= node
->Next();
2675 bool wxShape::GetAttachmentPosition(int attachment
, double *x
, double *y
,
2676 int nth
, int no_arcs
, wxLineShape
*line
)
2678 if (m_attachmentMode
== ATTACHMENT_MODE_NONE
)
2680 *x
= m_xpos
; *y
= m_ypos
;
2683 else if (m_attachmentMode
== ATTACHMENT_MODE_BRANCHING
)
2685 wxRealPoint pt
, stemPt
;
2686 GetBranchingAttachmentPoint(attachment
, nth
, pt
, stemPt
);
2691 else if (m_attachmentMode
== ATTACHMENT_MODE_EDGE
)
2693 if (m_attachmentPoints
.Number() > 0)
2695 wxNode
*node
= m_attachmentPoints
.First();
2698 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
2699 if (point
->m_id
== attachment
)
2701 *x
= (double)(m_xpos
+ point
->m_x
);
2702 *y
= (double)(m_ypos
+ point
->m_y
);
2705 node
= node
->Next();
2707 *x
= m_xpos
; *y
= m_ypos
;
2712 // Assume is rectangular
2714 GetBoundingBoxMax(&w
, &h
);
2715 double top
= (double)(m_ypos
+ h
/2.0);
2716 double bottom
= (double)(m_ypos
- h
/2.0);
2717 double left
= (double)(m_xpos
- w
/2.0);
2718 double right
= (double)(m_xpos
+ w
/2.0);
2720 bool isEnd
= (line
&& line
->IsEnd(this));
2722 int physicalAttachment
= LogicalToPhysicalAttachment(attachment
);
2725 switch (physicalAttachment
)
2729 wxRealPoint pt
= CalcSimpleAttachment(wxRealPoint(left
, bottom
), wxRealPoint(right
, bottom
),
2730 nth
, no_arcs
, line
);
2732 *x
= pt
.x
; *y
= pt
.y
;
2737 wxRealPoint pt
= CalcSimpleAttachment(wxRealPoint(right
, bottom
), wxRealPoint(right
, top
),
2738 nth
, no_arcs
, line
);
2740 *x
= pt
.x
; *y
= pt
.y
;
2745 wxRealPoint pt
= CalcSimpleAttachment(wxRealPoint(left
, top
), wxRealPoint(right
, top
),
2746 nth
, no_arcs
, line
);
2748 *x
= pt
.x
; *y
= pt
.y
;
2753 wxRealPoint pt
= CalcSimpleAttachment(wxRealPoint(left
, bottom
), wxRealPoint(left
, top
),
2754 nth
, no_arcs
, line
);
2756 *x
= pt
.x
; *y
= pt
.y
;
2771 void wxShape::GetBoundingBoxMax(double *w
, double *h
)
2774 GetBoundingBoxMin(&ww
, &hh
);
2775 if (m_shadowMode
!= SHADOW_NONE
)
2777 ww
+= m_shadowOffsetX
;
2778 hh
+= m_shadowOffsetY
;
2784 // Returns TRUE if image is a descendant of this composite
2785 bool wxShape::HasDescendant(wxShape
*image
)
2789 wxNode
*node
= m_children
.First();
2792 wxShape
*child
= (wxShape
*)node
->Data();
2793 bool ans
= child
->HasDescendant(image
);
2796 node
= node
->Next();
2801 // Clears points from a list of wxRealPoints, and clears list
2802 void wxShape::ClearPointList(wxList
& list
)
2804 wxNode
* node
= list
.First();
2807 wxRealPoint
* pt
= (wxRealPoint
*) node
->Data();
2810 node
= node
->Next();
2815 // Assuming the attachment lies along a vertical or horizontal line,
2816 // calculate the position on that point.
2817 wxRealPoint
wxShape::CalcSimpleAttachment(const wxRealPoint
& pt1
, const wxRealPoint
& pt2
,
2818 int nth
, int noArcs
, wxLineShape
* line
)
2820 bool isEnd
= (line
&& line
->IsEnd(this));
2822 // Are we horizontal or vertical?
2823 bool isHorizontal
= (oglRoughlyEqual(pt1
.y
, pt2
.y
) == TRUE
);
2829 wxRealPoint firstPoint
, secondPoint
;
2841 if (m_spaceAttachments
)
2843 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
2845 // Align line according to the next handle along
2846 wxRealPoint
*point
= line
->GetNextControlPoint(this);
2847 if (point
->x
< firstPoint
.x
)
2849 else if (point
->x
> secondPoint
.x
)
2855 x
= firstPoint
.x
+ (nth
+ 1)*(secondPoint
.x
- firstPoint
.x
)/(noArcs
+ 1);
2857 else x
= (secondPoint
.x
- firstPoint
.x
)/2.0; // Midpoint
2863 wxASSERT( oglRoughlyEqual(pt1
.x
, pt2
.x
) == TRUE
);
2865 wxRealPoint firstPoint
, secondPoint
;
2877 if (m_spaceAttachments
)
2879 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
2881 // Align line according to the next handle along
2882 wxRealPoint
*point
= line
->GetNextControlPoint(this);
2883 if (point
->y
< firstPoint
.y
)
2885 else if (point
->y
> secondPoint
.y
)
2891 y
= firstPoint
.y
+ (nth
+ 1)*(secondPoint
.y
- firstPoint
.y
)/(noArcs
+ 1);
2893 else y
= (secondPoint
.y
- firstPoint
.y
)/2.0; // Midpoint
2898 return wxRealPoint(x
, y
);
2901 // Return the zero-based position in m_lines of line.
2902 int wxShape::GetLinePosition(wxLineShape
* line
)
2905 for (i
= 0; i
< m_lines
.Number(); i
++)
2906 if ((wxLineShape
*) (m_lines
.Nth(i
)->Data()) == line
)
2916 // shoulder1 ->---------<- shoulder2
2918 // <- branching attachment point N-1
2920 // This function gets information about where branching connections go.
2921 // Returns FALSE if there are no lines at this attachment.
2922 bool wxShape::GetBranchingAttachmentInfo(int attachment
, wxRealPoint
& root
, wxRealPoint
& neck
,
2923 wxRealPoint
& shoulder1
, wxRealPoint
& shoulder2
)
2925 int physicalAttachment
= LogicalToPhysicalAttachment(attachment
);
2927 // Number of lines at this attachment.
2928 int lineCount
= GetAttachmentLineCount(attachment
);
2933 int totalBranchLength
= m_branchSpacing
* (lineCount
- 1);
2935 root
= GetBranchingAttachmentRoot(attachment
);
2937 // Assume that we have attachment points 0 to 3: top, right, bottom, left.
2938 switch (physicalAttachment
)
2943 neck
.y
= root
.y
- m_branchNeckLength
;
2945 shoulder1
.x
= root
.x
- (totalBranchLength
/2.0) ;
2946 shoulder2
.x
= root
.x
+ (totalBranchLength
/2.0) ;
2948 shoulder1
.y
= neck
.y
;
2949 shoulder2
.y
= neck
.y
;
2954 neck
.x
= root
.x
+ m_branchNeckLength
;
2957 shoulder1
.x
= neck
.x
;
2958 shoulder2
.x
= neck
.x
;
2960 shoulder1
.y
= neck
.y
- (totalBranchLength
/2.0) ;
2961 shoulder2
.y
= neck
.y
+ (totalBranchLength
/2.0) ;
2967 neck
.y
= root
.y
+ m_branchNeckLength
;
2969 shoulder1
.x
= root
.x
- (totalBranchLength
/2.0) ;
2970 shoulder2
.x
= root
.x
+ (totalBranchLength
/2.0) ;
2972 shoulder1
.y
= neck
.y
;
2973 shoulder2
.y
= neck
.y
;
2978 neck
.x
= root
.x
- m_branchNeckLength
;
2981 shoulder1
.x
= neck
.x
;
2982 shoulder2
.x
= neck
.x
;
2984 shoulder1
.y
= neck
.y
- (totalBranchLength
/2.0) ;
2985 shoulder2
.y
= neck
.y
+ (totalBranchLength
/2.0) ;
2990 wxFAIL_MSG( wxT("Unrecognised attachment point in GetBranchingAttachmentInfo.") );
2997 // n is the number of the adjoining line, from 0 to N-1 where N is the number of lines
2998 // at this attachment point.
2999 // Get the attachment point where the arc joins the stem, and also the point where the
3000 // the stem meets the shoulder.
3001 bool wxShape::GetBranchingAttachmentPoint(int attachment
, int n
, wxRealPoint
& pt
, wxRealPoint
& stemPt
)
3003 int physicalAttachment
= LogicalToPhysicalAttachment(attachment
);
3005 wxRealPoint root
, neck
, shoulder1
, shoulder2
;
3006 GetBranchingAttachmentInfo(attachment
, root
, neck
, shoulder1
, shoulder2
);
3008 // Assume that we have attachment points 0 to 3: top, right, bottom, left.
3009 switch (physicalAttachment
)
3013 pt
.y
= neck
.y
- m_branchStemLength
;
3014 pt
.x
= shoulder1
.x
+ n
*m_branchSpacing
;
3022 pt
.y
= neck
.y
+ m_branchStemLength
;
3023 pt
.x
= shoulder1
.x
+ n
*m_branchSpacing
;
3031 pt
.x
= neck
.x
+ m_branchStemLength
;
3032 pt
.y
= shoulder1
.y
+ n
*m_branchSpacing
;
3040 pt
.x
= neck
.x
- m_branchStemLength
;
3041 pt
.y
= shoulder1
.y
+ n
*m_branchSpacing
;
3049 wxFAIL_MSG( wxT("Unrecognised attachment point in GetBranchingAttachmentPoint.") );
3057 // Get the number of lines at this attachment position.
3058 int wxShape::GetAttachmentLineCount(int attachment
) const
3061 wxNode
* node
= m_lines
.First();
3064 wxLineShape
* lineShape
= (wxLineShape
*) node
->Data();
3065 if ((lineShape
->GetFrom() == this) && (lineShape
->GetAttachmentFrom() == attachment
))
3067 else if ((lineShape
->GetTo() == this) && (lineShape
->GetAttachmentTo() == attachment
))
3070 node
= node
->Next();
3075 // This function gets the root point at the given attachment.
3076 wxRealPoint
wxShape::GetBranchingAttachmentRoot(int attachment
)
3078 int physicalAttachment
= LogicalToPhysicalAttachment(attachment
);
3082 double width
, height
;
3083 GetBoundingBoxMax(& width
, & height
);
3085 // Assume that we have attachment points 0 to 3: top, right, bottom, left.
3086 switch (physicalAttachment
)
3091 root
.y
= GetY() - height
/2.0;
3096 root
.x
= GetX() + width
/2.0;
3103 root
.y
= GetY() + height
/2.0;
3108 root
.x
= GetX() - width
/2.0;
3114 wxFAIL_MSG( wxT("Unrecognised attachment point in GetBranchingAttachmentRoot.") );
3121 // Draw or erase the branches (not the actual arcs though)
3122 void wxShape::OnDrawBranches(wxDC
& dc
, int attachment
, bool erase
)
3124 int count
= GetAttachmentLineCount(attachment
);
3128 wxRealPoint root
, neck
, shoulder1
, shoulder2
;
3129 GetBranchingAttachmentInfo(attachment
, root
, neck
, shoulder1
, shoulder2
);
3133 dc
.SetPen(*wxWHITE_PEN
);
3134 dc
.SetBrush(*wxWHITE_BRUSH
);
3138 dc
.SetPen(*wxBLACK_PEN
);
3139 dc
.SetBrush(*wxBLACK_BRUSH
);
3143 dc
.DrawLine((long) root
.x
, (long) root
.y
, (long) neck
.x
, (long) neck
.y
);
3147 // Draw shoulder-to-shoulder line
3148 dc
.DrawLine((long) shoulder1
.x
, (long) shoulder1
.y
, (long) shoulder2
.x
, (long) shoulder2
.y
);
3150 // Draw all the little branches
3152 for (i
= 0; i
< count
; i
++)
3154 wxRealPoint pt
, stemPt
;
3155 GetBranchingAttachmentPoint(attachment
, i
, pt
, stemPt
);
3156 dc
.DrawLine((long) stemPt
.x
, (long) stemPt
.y
, (long) pt
.x
, (long) pt
.y
);
3158 if ((GetBranchStyle() & BRANCHING_ATTACHMENT_BLOB
) && (count
> 1))
3161 // dc.DrawEllipse((long) (stemPt.x + 0.5 - (blobSize/2.0)), (long) (stemPt.y + 0.5 - (blobSize/2.0)), blobSize, blobSize);
3162 dc
.DrawEllipse((long) (stemPt
.x
- (blobSize
/2.0)), (long) (stemPt
.y
- (blobSize
/2.0)), blobSize
, blobSize
);
3167 // Draw or erase the branches (not the actual arcs though)
3168 void wxShape::OnDrawBranches(wxDC
& dc
, bool erase
)
3170 if (m_attachmentMode
!= ATTACHMENT_MODE_BRANCHING
)
3173 int count
= GetNumberOfAttachments();
3175 for (i
= 0; i
< count
; i
++)
3176 OnDrawBranches(dc
, i
, erase
);
3179 // Only get the attachment position at the _edge_ of the shape, ignoring
3180 // branching mode. This is used e.g. to indicate the edge of interest, not the point
3181 // on the attachment branch.
3182 bool wxShape::GetAttachmentPositionEdge(int attachment
, double *x
, double *y
,
3183 int nth
, int no_arcs
, wxLineShape
*line
)
3185 int oldMode
= m_attachmentMode
;
3187 // Calculate as if to edge, not branch
3188 if (m_attachmentMode
== ATTACHMENT_MODE_BRANCHING
)
3189 m_attachmentMode
= ATTACHMENT_MODE_EDGE
;
3190 bool success
= GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
, line
);
3191 m_attachmentMode
= oldMode
;
3196 // Rotate the standard attachment point from physical (0 is always North)
3197 // to logical (0 -> 1 if rotated by 90 degrees)
3198 int wxShape::PhysicalToLogicalAttachment(int physicalAttachment
) const
3200 const double pi
= 3.1415926535897932384626433832795 ;
3202 if (oglRoughlyEqual(GetRotation(), 0.0))
3204 i
= physicalAttachment
;
3206 else if (oglRoughlyEqual(GetRotation(), (pi
/2.0)))
3208 i
= physicalAttachment
- 1;
3210 else if (oglRoughlyEqual(GetRotation(), pi
))
3212 i
= physicalAttachment
- 2;
3214 else if (oglRoughlyEqual(GetRotation(), (3.0*pi
/2.0)))
3216 i
= physicalAttachment
- 3;
3219 // Can't handle -- assume the same.
3220 return physicalAttachment
;
3228 // Rotate the standard attachment point from logical
3229 // to physical (0 is always North)
3230 int wxShape::LogicalToPhysicalAttachment(int logicalAttachment
) const
3232 const double pi
= 3.1415926535897932384626433832795 ;
3234 if (oglRoughlyEqual(GetRotation(), 0.0))
3236 i
= logicalAttachment
;
3238 else if (oglRoughlyEqual(GetRotation(), (pi
/2.0)))
3240 i
= logicalAttachment
+ 1;
3242 else if (oglRoughlyEqual(GetRotation(), pi
))
3244 i
= logicalAttachment
+ 2;
3246 else if (oglRoughlyEqual(GetRotation(), (3.0*pi
/2.0)))
3248 i
= logicalAttachment
+ 3;
3251 // Can't handle -- assume the same.
3252 return logicalAttachment
;
3260 void wxShape::Rotate(double WXUNUSED(x
), double WXUNUSED(y
), double theta
)
3262 const double pi
= 3.1415926535897932384626433832795 ;
3264 if (m_rotation
< 0.0)
3268 else if (m_rotation
> 2*pi
)
3275 wxPen
wxShape::GetBackgroundPen()
3279 wxColour c
= GetCanvas()->GetBackgroundColour();
3280 return wxPen(c
, 1, wxSOLID
);
3282 return * g_oglWhiteBackgroundPen
;
3286 wxBrush
wxShape::GetBackgroundBrush()
3290 wxColour c
= GetCanvas()->GetBackgroundColour();
3291 return wxBrush(c
, wxSOLID
);
3293 return * g_oglWhiteBackgroundBrush
;