1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Basic OGL classes
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "basic.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include <wx/wxprec.h>
28 #include <wx/wxexpr.h>
49 // Control point types
50 // Rectangle and most other shapes
51 #define CONTROL_POINT_VERTICAL 1
52 #define CONTROL_POINT_HORIZONTAL 2
53 #define CONTROL_POINT_DIAGONAL 3
56 #define CONTROL_POINT_ENDPOINT_TO 4
57 #define CONTROL_POINT_ENDPOINT_FROM 5
58 #define CONTROL_POINT_LINE 6
60 IMPLEMENT_DYNAMIC_CLASS(wxShapeTextLine
, wxObject
)
61 IMPLEMENT_DYNAMIC_CLASS(wxAttachmentPoint
, wxObject
)
63 wxShapeTextLine::wxShapeTextLine(float the_x
, float the_y
, const wxString
& the_line
)
65 m_x
= the_x
; m_y
= the_y
; m_line
= the_line
;
68 wxShapeTextLine::~wxShapeTextLine()
72 IMPLEMENT_ABSTRACT_CLASS(wxShapeEvtHandler
, wxObject
)
74 wxShapeEvtHandler::wxShapeEvtHandler(wxShapeEvtHandler
*prev
, wxShape
*shape
)
76 m_previousHandler
= prev
;
77 m_handlerShape
= shape
;
80 wxShapeEvtHandler::~wxShapeEvtHandler()
84 void wxShapeEvtHandler::OnDelete()
86 if (this != GetShape())
90 void wxShapeEvtHandler::OnDraw(wxDC
& dc
)
92 if (m_previousHandler
)
93 m_previousHandler
->OnDraw(dc
);
96 void wxShapeEvtHandler::OnMoveLinks(wxDC
& dc
)
98 if (m_previousHandler
)
99 m_previousHandler
->OnMoveLinks(dc
);
102 void wxShapeEvtHandler::OnMoveLink(wxDC
& dc
, bool moveControlPoints
)
104 if (m_previousHandler
)
105 m_previousHandler
->OnMoveLink(dc
, moveControlPoints
);
108 void wxShapeEvtHandler::OnDrawContents(wxDC
& dc
)
110 if (m_previousHandler
)
111 m_previousHandler
->OnDrawContents(dc
);
114 void wxShapeEvtHandler::OnSize(float x
, float y
)
116 if (m_previousHandler
)
117 m_previousHandler
->OnSize(x
, y
);
120 bool wxShapeEvtHandler::OnMovePre(wxDC
& dc
, float x
, float y
, float old_x
, float old_y
, bool display
)
122 if (m_previousHandler
)
123 return m_previousHandler
->OnMovePre(dc
, x
, y
, old_x
, old_y
, display
);
128 void wxShapeEvtHandler::OnMovePost(wxDC
& dc
, float x
, float y
, float old_x
, float old_y
, bool display
)
130 if (m_previousHandler
)
131 m_previousHandler
->OnMovePost(dc
, x
, y
, old_x
, old_y
, display
);
134 void wxShapeEvtHandler::OnErase(wxDC
& dc
)
136 if (m_previousHandler
)
137 m_previousHandler
->OnErase(dc
);
140 void wxShapeEvtHandler::OnEraseContents(wxDC
& dc
)
142 if (m_previousHandler
)
143 m_previousHandler
->OnEraseContents(dc
);
146 void wxShapeEvtHandler::OnHighlight(wxDC
& dc
)
148 if (m_previousHandler
)
149 m_previousHandler
->OnHighlight(dc
);
152 void wxShapeEvtHandler::OnLeftClick(float x
, float y
, int keys
, int attachment
)
154 if (m_previousHandler
)
155 m_previousHandler
->OnLeftClick(x
, y
, keys
, attachment
);
158 void wxShapeEvtHandler::OnRightClick(float x
, float y
, int keys
, int attachment
)
160 if (m_previousHandler
)
161 m_previousHandler
->OnRightClick(x
, y
, keys
, attachment
);
164 void wxShapeEvtHandler::OnDragLeft(bool draw
, float x
, float y
, int keys
, int attachment
)
166 if (m_previousHandler
)
167 m_previousHandler
->OnDragLeft(draw
, x
, y
, keys
, attachment
);
170 void wxShapeEvtHandler::OnBeginDragLeft(float x
, float y
, int keys
, int attachment
)
172 if (m_previousHandler
)
173 m_previousHandler
->OnBeginDragLeft(x
, y
, keys
, attachment
);
176 void wxShapeEvtHandler::OnEndDragLeft(float x
, float y
, int keys
, int attachment
)
178 if (m_previousHandler
)
179 m_previousHandler
->OnEndDragLeft(x
, y
, keys
, attachment
);
182 void wxShapeEvtHandler::OnDragRight(bool draw
, float x
, float y
, int keys
, int attachment
)
184 if (m_previousHandler
)
185 m_previousHandler
->OnDragRight(draw
, x
, y
, keys
, attachment
);
188 void wxShapeEvtHandler::OnBeginDragRight(float x
, float y
, int keys
, int attachment
)
190 if (m_previousHandler
)
191 m_previousHandler
->OnBeginDragRight(x
, y
, keys
, attachment
);
194 void wxShapeEvtHandler::OnEndDragRight(float x
, float y
, int keys
, int attachment
)
196 if (m_previousHandler
)
197 m_previousHandler
->OnEndDragRight(x
, y
, keys
, attachment
);
200 void wxShapeEvtHandler::OnDrawOutline(wxDC
& dc
, float x
, float y
, float w
, float h
)
202 if (m_previousHandler
)
203 m_previousHandler
->OnDrawOutline(dc
, x
, y
, w
, h
);
206 void wxShapeEvtHandler::OnDrawControlPoints(wxDC
& dc
)
208 if (m_previousHandler
)
209 m_previousHandler
->OnDrawControlPoints(dc
);
212 void wxShapeEvtHandler::OnEraseControlPoints(wxDC
& dc
)
214 if (m_previousHandler
)
215 m_previousHandler
->OnEraseControlPoints(dc
);
218 IMPLEMENT_ABSTRACT_CLASS(wxShape
, wxShapeEvtHandler
)
220 wxShape::wxShape(wxShapeCanvas
*can
)
222 m_eventHandler
= this;
223 SetHandlerShape(this);
227 m_xpos
= 0.0; m_ypos
= 0.0;
229 m_brush
= wxWHITE_BRUSH
;
230 m_font
= g_oglNormalFont
;
231 m_textColour
= wxBLACK
;
232 m_textColourName
= "BLACK";
236 m_attachmentMode
= FALSE
;
237 m_spaceAttachments
= TRUE
;
238 m_disableLabel
= FALSE
;
239 m_fixedWidth
= FALSE
;
240 m_fixedHeight
= FALSE
;
241 m_drawHandles
= TRUE
;
242 m_sensitivity
= OP_ALL
;
245 m_formatMode
= FORMAT_CENTRE_HORIZ
| FORMAT_CENTRE_VERT
;
246 m_shadowMode
= SHADOW_NONE
;
247 m_shadowOffsetX
= 6.0;
248 m_shadowOffsetY
= 6.0;
249 m_shadowBrush
= wxBLACK_BRUSH
;
253 m_centreResize
= TRUE
;
254 m_highlighted
= FALSE
;
257 // Set up a default region. Much of the above will be put into
258 // the region eventually (the duplication is for compatibility)
259 wxShapeRegion
*region
= new wxShapeRegion
;
260 m_regions
.Append(region
);
261 region
->SetName("0");
262 region
->SetFont(g_oglNormalFont
);
263 region
->SetFormatMode(FORMAT_CENTRE_HORIZ
| FORMAT_CENTRE_VERT
);
264 region
->SetColour("BLACK");
270 m_parent
->GetChildren().DeleteObject(this);
277 m_canvas
->RemoveShape(this);
279 GetEventHandler()->OnDelete();
282 void wxShape::SetHighlight(bool hi
, bool recurse
)
287 wxNode
*node
= m_children
.First();
290 wxShape
*child
= (wxShape
*)node
->Data();
291 child
->SetHighlight(hi
, recurse
);
297 void wxShape::SetSensitivityFilter(int sens
, bool recursive
)
299 if (sens
& OP_DRAG_LEFT
)
304 m_sensitivity
= sens
;
307 wxNode
*node
= m_children
.First();
310 wxShape
*obj
= (wxShape
*)node
->Data();
311 obj
->SetSensitivityFilter(sens
, TRUE
);
317 void wxShape::SetDraggable(bool drag
, bool recursive
)
321 m_sensitivity
|= OP_DRAG_LEFT
;
323 if (m_sensitivity
& OP_DRAG_LEFT
)
324 m_sensitivity
= m_sensitivity
- OP_DRAG_LEFT
;
328 wxNode
*node
= m_children
.First();
331 wxShape
*obj
= (wxShape
*)node
->Data();
332 obj
->SetDraggable(drag
, TRUE
);
338 void wxShape::SetDrawHandles(bool drawH
)
340 m_drawHandles
= drawH
;
341 wxNode
*node
= m_children
.First();
344 wxShape
*obj
= (wxShape
*)node
->Data();
345 obj
->SetDrawHandles(drawH
);
350 void wxShape::SetShadowMode(int mode
, bool redraw
)
352 if (redraw
&& GetCanvas())
354 wxClientDC
dc(GetCanvas());
355 GetCanvas()->PrepareDC(dc
);
368 void wxShape::SetCanvas(wxShapeCanvas
*theCanvas
)
370 m_canvas
= theCanvas
;
371 wxNode
*node
= m_children
.First();
374 wxShape
*child
= (wxShape
*)node
->Data();
375 child
->SetCanvas(theCanvas
);
380 void wxShape::AddToCanvas(wxShapeCanvas
*theCanvas
, wxShape
*addAfter
)
382 theCanvas
->AddShape(this, addAfter
);
383 wxNode
*node
= m_children
.First();
384 wxShape
*lastImage
= this;
387 wxShape
*object
= (wxShape
*)node
->Data();
388 object
->AddToCanvas(theCanvas
, lastImage
);
395 // Insert at front of canvas
396 void wxShape::InsertInCanvas(wxShapeCanvas
*theCanvas
)
398 theCanvas
->InsertShape(this);
399 wxNode
*node
= m_children
.First();
400 wxShape
*lastImage
= this;
403 wxShape
*object
= (wxShape
*)node
->Data();
404 object
->AddToCanvas(theCanvas
, lastImage
);
411 void wxShape::RemoveFromCanvas(wxShapeCanvas
*theCanvas
)
415 theCanvas
->RemoveShape(this);
416 wxNode
*node
= m_children
.First();
419 wxShape
*object
= (wxShape
*)node
->Data();
420 object
->RemoveFromCanvas(theCanvas
);
426 void wxShape::ClearAttachments()
428 wxNode
*node
= m_attachmentPoints
.First();
431 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
435 m_attachmentPoints
.Clear();
438 void wxShape::ClearText(int regionId
)
442 m_text
.DeleteContents(TRUE
);
444 m_text
.DeleteContents(FALSE
);
446 wxNode
*node
= m_regions
.Nth(regionId
);
449 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
453 void wxShape::ClearRegions()
455 wxNode
*node
= m_regions
.First();
458 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
459 wxNode
*next
= node
->Next();
466 void wxShape::AddRegion(wxShapeRegion
*region
)
468 m_regions
.Append(region
);
471 void wxShape::SetDefaultRegionSize()
473 wxNode
*node
= m_regions
.First();
475 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
477 GetBoundingBoxMin(&w
, &h
);
478 region
->SetSize(w
, h
);
481 bool wxShape::HitTest(float x
, float y
, int *attachment
, float *distance
)
486 float width
= 0.0, height
= 0.0;
487 GetBoundingBoxMin(&width
, &height
);
488 if (fabs(width
) < 4.0) width
= 4.0;
489 if (fabs(height
) < 4.0) height
= 4.0;
491 width
+= (float)4.0; height
+= (float)4.0; // Allowance for inaccurate mousing
493 float left
= (float)(m_xpos
- (width
/2.0));
494 float top
= (float)(m_ypos
- (height
/2.0));
495 float right
= (float)(m_xpos
+ (width
/2.0));
496 float bottom
= (float)(m_ypos
+ (height
/2.0));
498 int nearest_attachment
= 0;
501 // If within the bounding box, check the attachment points
502 // within the object.
504 if (x
>= left
&& x
<= right
&& y
>= top
&& y
<= bottom
)
506 int n
= GetNumberOfAttachments();
507 float nearest
= 999999.0;
509 for (int i
= 0; i
< n
; i
++)
512 if (GetAttachmentPosition(i
, &xp
, &yp
))
514 float l
= (float)sqrt(((xp
- x
) * (xp
- x
)) +
515 ((yp
- y
) * (yp
- y
)));
520 nearest_attachment
= i
;
524 *attachment
= nearest_attachment
;
531 // Format a text string according to the region size, adding
532 // strings with positions to region text list
534 static bool GraphicsInSizeToContents
= FALSE
; // Infinite recursion elimination
535 void wxShape::FormatText(wxDC
& dc
, const wxString
& s
, int i
)
540 if (m_regions
.Number() < 1)
542 wxNode
*node
= m_regions
.Nth(i
);
546 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
548 dc
.SetFont(region
->GetFont());
550 region
->GetSize(&w
, &h
);
552 wxList
*string_list
= ::FormatText(dc
, s
, (w
-5), (h
-5), region
->GetFormatMode());
553 node
= string_list
->First();
556 char *s
= (char *)node
->Data();
557 wxShapeTextLine
*line
= new wxShapeTextLine(0.0, 0.0, s
);
558 region
->GetFormattedText().Append((wxObject
*)line
);
560 node
= string_list
->First();
565 // Don't try to resize an object with more than one image (this case should be dealt
566 // with by overriden handlers)
567 if ((region
->GetFormatMode() & FORMAT_SIZE_TO_CONTENTS
) &&
568 (region
->GetFormattedText().Number() > 0) &&
569 (m_regions
.Number() == 1) && !GraphicsInSizeToContents
)
571 GetCentredTextExtent(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, w
, h
, &actualW
, &actualH
);
572 if ((actualW
+m_textMarginX
!= w
) || (actualH
+m_textMarginY
!= h
))
574 // If we are a descendant of a composite, must make sure the composite gets
576 wxShape
*topAncestor
= GetTopAncestor();
578 if (topAncestor
!= this)
580 // Make sure we don't recurse infinitely
581 GraphicsInSizeToContents
= TRUE
;
583 wxCompositeShape
*composite
= (wxCompositeShape
*)topAncestor
;
584 composite
->Erase(dc
);
585 SetSize(actualW
+m_textMarginX
, actualH
+m_textMarginY
);
586 Move(dc
, m_xpos
, m_ypos
);
587 composite
->CalculateSize();
588 if (composite
->Selected())
590 composite
->DeleteControlPoints(& dc
);
591 composite
->MakeControlPoints();
592 composite
->MakeMandatoryControlPoints();
594 // Where infinite recursion might happen if we didn't stop it
597 GraphicsInSizeToContents
= FALSE
;
602 SetSize(actualW
+m_textMarginX
, actualH
+m_textMarginY
);
603 Move(dc
, m_xpos
, m_ypos
);
605 SetSize(actualW
+m_textMarginX
, actualH
+m_textMarginY
);
606 Move(dc
, m_xpos
, m_ypos
);
610 CentreText(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, actualW
, actualH
, region
->GetFormatMode());
614 void wxShape::Recentre(wxDC
& dc
)
617 GetBoundingBoxMin(&w
, &h
);
619 int noRegions
= m_regions
.Number();
620 for (int i
= 0; i
< noRegions
; i
++)
622 wxNode
*node
= m_regions
.Nth(i
);
625 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
626 CentreText(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, w
, h
, region
->GetFormatMode());
631 bool wxShape::GetPerimeterPoint(float x1
, float y1
,
633 float *x3
, float *y3
)
638 void wxShape::SetPen(wxPen
*the_pen
)
643 void wxShape::SetBrush(wxBrush
*the_brush
)
648 // Get the top-most (non-division) ancestor, or self
649 wxShape
*wxShape::GetTopAncestor()
654 if (GetParent()->IsKindOf(CLASSINFO(wxDivisionShape
)))
656 else return GetParent()->GetTopAncestor();
663 void wxShape::SetFont(wxFont
*the_font
, int regionId
)
666 wxNode
*node
= m_regions
.Nth(regionId
);
669 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
670 region
->SetFont(the_font
);
673 wxFont
*wxShape::GetFont(int n
) const
675 wxNode
*node
= m_regions
.Nth(n
);
678 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
679 return region
->GetFont();
682 void wxShape::SetFormatMode(int mode
, int regionId
)
684 wxNode
*node
= m_regions
.Nth(regionId
);
687 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
688 region
->SetFormatMode(mode
);
691 int wxShape::GetFormatMode(int regionId
) const
693 wxNode
*node
= m_regions
.Nth(regionId
);
696 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
697 return region
->GetFormatMode();
700 void wxShape::SetTextColour(const wxString
& the_colour
, int regionId
)
702 wxColour
*wxcolour
= wxTheColourDatabase
->FindColour(the_colour
);
703 m_textColour
= wxcolour
;
704 m_textColourName
= the_colour
;
706 wxNode
*node
= m_regions
.Nth(regionId
);
709 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
710 region
->SetColour(the_colour
);
713 wxString
wxShape::GetTextColour(int regionId
) const
715 wxNode
*node
= m_regions
.Nth(regionId
);
718 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
719 return region
->GetColour();
722 void wxShape::SetRegionName(const wxString
& name
, int regionId
)
724 wxNode
*node
= m_regions
.Nth(regionId
);
727 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
728 region
->SetName(name
);
731 wxString
wxShape::GetRegionName(int regionId
)
733 wxNode
*node
= m_regions
.Nth(regionId
);
736 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
737 return region
->GetName();
740 int wxShape::GetRegionId(const wxString
& name
)
742 wxNode
*node
= m_regions
.First();
746 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
747 if (region
->GetName() == name
)
755 // Name all m_regions in all subimages recursively.
756 void wxShape::NameRegions(const wxString
& parentName
)
758 int n
= GetNumberOfTextRegions();
760 for (int i
= 0; i
< n
; i
++)
762 if (parentName
.Length() > 0)
763 sprintf(buf
, "%s.%d", (const char*) parentName
, i
);
765 sprintf(buf
, "%d", i
);
766 SetRegionName(buf
, i
);
768 wxNode
*node
= m_children
.First();
772 wxShape
*child
= (wxShape
*)node
->Data();
773 if (parentName
.Length() > 0)
774 sprintf(buf
, "%s.%d", (const char*) parentName
, j
);
776 sprintf(buf
, "%d", j
);
777 child
->NameRegions(buf
);
783 // Get a region by name, possibly looking recursively into composites.
784 wxShape
*wxShape::FindRegion(const wxString
& name
, int *regionId
)
786 int id
= GetRegionId(name
);
793 wxNode
*node
= m_children
.First();
796 wxShape
*child
= (wxShape
*)node
->Data();
797 wxShape
*actualImage
= child
->FindRegion(name
, regionId
);
805 // Finds all region names for this image (composite or simple).
806 // Supply empty string list.
807 void wxShape::FindRegionNames(wxStringList
& list
)
809 int n
= GetNumberOfTextRegions();
810 for (int i
= 0; i
< n
; i
++)
812 wxString
name(GetRegionName(i
));
813 list
.Add((const char*) name
);
816 wxNode
*node
= m_children
.First();
819 wxShape
*child
= (wxShape
*)node
->Data();
820 child
->FindRegionNames(list
);
825 void wxShape::AssignNewIds()
829 wxNode
*node
= m_children
.First();
832 wxShape
*child
= (wxShape
*)node
->Data();
833 child
->AssignNewIds();
838 void wxShape::OnDraw(wxDC
& dc
)
842 void wxShape::OnMoveLinks(wxDC
& dc
)
844 // Want to set the ends of all attached links
845 // to point to/from this object
847 wxNode
*current
= m_lines
.First();
850 wxLineShape
*line
= (wxLineShape
*)current
->Data();
851 line
->GetEventHandler()->OnMoveLink(dc
);
852 current
= current
->Next();
857 void wxShape::OnDrawContents(wxDC
& dc
)
859 float bound_x
, bound_y
;
860 GetBoundingBoxMin(&bound_x
, &bound_y
);
861 if (m_regions
.Number() < 1) return;
863 if (m_pen
) dc
.SetPen(m_pen
);
865 wxShapeRegion
*region
= (wxShapeRegion
*)m_regions
.First()->Data();
866 if (region
->GetFont()) dc
.SetFont(region
->GetFont());
868 dc
.SetTextForeground(* (region
->GetActualColourObject()));
869 dc
.SetBackgroundMode(wxTRANSPARENT
);
872 CentreText(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, bound_x
, bound_y
, region
->GetFormatMode());
875 if (!GetDisableLabel())
877 DrawFormattedText(dc
, &(region
->GetFormattedText()), m_xpos
, m_ypos
, bound_x
, bound_y
, region
->GetFormatMode());
881 void wxShape::DrawContents(wxDC
& dc
)
883 GetEventHandler()->OnDrawContents(dc
);
886 void wxShape::OnSize(float x
, float y
)
890 bool wxShape::OnMovePre(wxDC
& dc
, float x
, float y
, float old_x
, float old_y
, bool display
)
895 void wxShape::OnMovePost(wxDC
& dc
, float x
, float y
, float old_x
, float old_y
, bool display
)
899 void wxShape::OnErase(wxDC
& dc
)
905 wxNode
*current
= m_lines
.First();
908 wxLineShape
*line
= (wxLineShape
*)current
->Data();
909 line
->GetEventHandler()->OnErase(dc
);
910 current
= current
->Next();
912 GetEventHandler()->OnEraseContents(dc
);
915 void wxShape::OnEraseContents(wxDC
& dc
)
920 float maxX
, maxY
, minX
, minY
;
923 GetBoundingBoxMin(&minX
, &minY
);
924 GetBoundingBoxMax(&maxX
, &maxY
);
925 float topLeftX
= (float)(xp
- (maxX
/ 2.0) - 2.0);
926 float topLeftY
= (float)(yp
- (maxY
/ 2.0) - 2.0);
930 penWidth
= m_pen
->GetWidth();
932 dc
.SetPen(white_background_pen
);
933 dc
.SetBrush(white_background_brush
);
934 dc
.DrawRectangle((float)(topLeftX
- penWidth
), (float)(topLeftY
- penWidth
),
935 (float)(maxX
+ penWidth
*2.0 + 4.0), (float)(maxY
+ penWidth
*2.0 + 4.0));
938 void wxShape::EraseLinks(wxDC
& dc
, int attachment
, bool recurse
)
943 wxNode
*current
= m_lines
.First();
946 wxLineShape
*line
= (wxLineShape
*)current
->Data();
947 if (attachment
== -1 || ((line
->GetTo() == this && line
->GetAttachmentTo() == attachment
) ||
948 (line
->GetFrom() == this && line
->GetAttachmentFrom() == attachment
)))
949 line
->GetEventHandler()->OnErase(dc
);
950 current
= current
->Next();
954 wxNode
*node
= m_children
.First();
957 wxShape
*child
= (wxShape
*)node
->Data();
958 child
->EraseLinks(dc
, attachment
, recurse
);
964 void wxShape::DrawLinks(wxDC
& dc
, int attachment
, bool recurse
)
969 wxNode
*current
= m_lines
.First();
972 wxLineShape
*line
= (wxLineShape
*)current
->Data();
973 if (attachment
== -1 ||
974 (line
->GetTo() == this && line
->GetAttachmentTo() == attachment
) ||
975 (line
->GetFrom() == this && line
->GetAttachmentFrom() == attachment
))
977 current
= current
->Next();
981 wxNode
*node
= m_children
.First();
984 wxShape
*child
= (wxShape
*)node
->Data();
985 child
->DrawLinks(dc
, attachment
, recurse
);
991 void wxShape::MoveLineToNewAttachment(wxDC
& dc
, wxLineShape
*to_move
,
997 // Is (x, y) on this object? If so, find the new attachment point
998 // the user has moved the point to
999 bool hit
= HitTest(x
, y
, &new_point
, &distance
);
1006 if (to_move
->GetTo() == this)
1007 old_attachment
= to_move
->GetAttachmentTo();
1009 old_attachment
= to_move
->GetAttachmentFrom();
1011 // Delete the line object from the list of links; we're going to move
1012 // it to another position in the list
1013 m_lines
.DeleteObject(to_move
);
1015 float old_x
= (float) -9999.9;
1016 float old_y
= (float) -9999.9;
1018 wxNode
*node
= m_lines
.First();
1021 while (node
&& !found
)
1023 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1024 if ((line
->GetTo() == this && old_attachment
== line
->GetAttachmentTo()) ||
1025 (line
->GetFrom() == this && old_attachment
== line
->GetAttachmentFrom()))
1027 float startX
, startY
, endX
, endY
;
1029 line
->GetEnds(&startX
, &startY
, &endX
, &endY
);
1030 if (line
->GetTo() == this)
1032 // xp = line->m_xpos2 + line->m_xpos;
1033 // yp = line->m_ypos2 + line->m_ypos;
1038 // xp = line->m_xpos1 + line->m_xpos;
1039 // yp = line->m_ypos1 + line->m_ypos;
1044 switch (old_attachment
)
1049 if (x
> old_x
&& x
<= xp
)
1052 m_lines
.Insert(node
, to_move
);
1059 if (y
> old_y
&& y
<= yp
)
1062 m_lines
.Insert(node
, to_move
);
1070 node
= node
->Next();
1073 m_lines
.Append(to_move
);
1076 // Reorders the lines coming into the node image at this attachment
1077 // position, in the order in which they appear in linesToSort.
1078 // Any remaining lines not in the list will be added to the end.
1079 void wxShape::SortLines(int attachment
, wxList
& linesToSort
)
1081 // This is a temporary store of all the lines at this attachment
1082 // point. We'll tick them off as we've processed them.
1083 wxList linesAtThisAttachment
;
1085 wxNode
*node
= m_lines
.First();
1088 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1089 wxNode
*next
= node
->Next();
1090 if ((line
->GetTo() == this && line
->GetAttachmentTo() == attachment
) ||
1091 (line
->GetFrom() == this && line
->GetAttachmentFrom() == attachment
))
1093 linesAtThisAttachment
.Append(line
);
1097 else node
= node
->Next();
1100 node
= linesToSort
.First();
1103 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1104 if (linesAtThisAttachment
.Member(line
))
1107 linesAtThisAttachment
.DeleteObject(line
);
1108 m_lines
.Append(line
);
1110 node
= node
->Next();
1113 // Now add any lines that haven't been listed in linesToSort.
1114 node
= linesAtThisAttachment
.First();
1117 wxLineShape
*line
= (wxLineShape
*)node
->Data();
1118 m_lines
.Append(line
);
1119 node
= node
->Next();
1123 void wxShape::OnHighlight(wxDC
& dc
)
1127 void wxShape::OnLeftClick(float x
, float y
, int keys
, int attachment
)
1129 if ((m_sensitivity
& OP_CLICK_LEFT
) != OP_CLICK_LEFT
)
1135 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1136 m_parent
->GetEventHandler()->OnLeftClick(x
, y
, keys
, attachment
);
1142 void wxShape::OnRightClick(float x
, float y
, int keys
, int attachment
)
1144 if ((m_sensitivity
& OP_CLICK_RIGHT
) != OP_CLICK_RIGHT
)
1150 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1151 m_parent
->GetEventHandler()->OnRightClick(x
, y
, keys
, attachment
);
1157 float DragOffsetX
= 0.0;
1158 float DragOffsetY
= 0.0;
1160 void wxShape::OnDragLeft(bool draw
, float x
, float y
, int keys
, int attachment
)
1162 if ((m_sensitivity
& OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
1168 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1169 m_parent
->GetEventHandler()->OnDragLeft(draw
, x
, y
, keys
, attachment
);
1174 wxClientDC
dc(GetCanvas());
1175 GetCanvas()->PrepareDC(dc
);
1177 dc
.SetLogicalFunction(wxXOR
);
1179 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1180 dc
.SetPen(dottedPen
);
1181 dc
.SetBrush(* wxTRANSPARENT_BRUSH
);
1184 xx
= x
+ DragOffsetX
;
1185 yy
= y
+ DragOffsetY
;
1187 m_canvas
->Snap(&xx
, &yy
);
1188 // m_xpos = xx; m_ypos = yy;
1190 GetBoundingBoxMax(&w
, &h
);
1191 GetEventHandler()->OnDrawOutline(dc
, xx
, yy
, w
, h
);
1194 void wxShape::OnBeginDragLeft(float x
, float y
, int keys
, int attachment
)
1196 if ((m_sensitivity
& OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
1202 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1203 m_parent
->GetEventHandler()->OnBeginDragLeft(x
, y
, keys
, attachment
);
1208 DragOffsetX
= m_xpos
- x
;
1209 DragOffsetY
= m_ypos
- y
;
1211 wxClientDC
dc(GetCanvas());
1212 GetCanvas()->PrepareDC(dc
);
1216 xx
= x
+ DragOffsetX
;
1217 yy
= y
+ DragOffsetY
;
1218 m_canvas
->Snap(&xx
, &yy
);
1219 // m_xpos = xx; m_ypos = yy;
1220 dc
.SetLogicalFunction(wxXOR
);
1222 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
1223 dc
.SetPen(dottedPen
);
1224 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
1227 GetBoundingBoxMax(&w
, &h
);
1228 GetEventHandler()->OnDrawOutline(dc
, xx
, yy
, w
, h
);
1229 m_canvas
->CaptureMouse();
1232 void wxShape::OnEndDragLeft(float x
, float y
, int keys
, int attachment
)
1234 m_canvas
->ReleaseMouse();
1235 if ((m_sensitivity
& OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
1241 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1242 m_parent
->GetEventHandler()->OnEndDragLeft(x
, y
, keys
, attachment
);
1247 wxClientDC
dc(GetCanvas());
1248 GetCanvas()->PrepareDC(dc
);
1250 dc
.SetLogicalFunction(wxCOPY
);
1252 float xx
= x
+ DragOffsetX
;
1253 float yy
= y
+ DragOffsetY
;
1254 m_canvas
->Snap(&xx
, &yy
);
1255 // canvas->Snap(&m_xpos, &m_ypos);
1257 if (m_canvas
&& !m_canvas
->GetQuickEditMode()) m_canvas
->Redraw(dc
);
1260 void wxShape::OnDragRight(bool draw
, float x
, float y
, int keys
, int attachment
)
1262 if ((m_sensitivity
& OP_DRAG_RIGHT
) != OP_DRAG_RIGHT
)
1268 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1269 m_parent
->GetEventHandler()->OnDragRight(draw
, x
, y
, keys
, attachment
);
1275 void wxShape::OnBeginDragRight(float x
, float y
, int keys
, int attachment
)
1277 if ((m_sensitivity
& OP_DRAG_RIGHT
) != OP_DRAG_RIGHT
)
1283 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1284 m_parent
->GetEventHandler()->OnBeginDragRight(x
, y
, keys
, attachment
);
1290 void wxShape::OnEndDragRight(float x
, float y
, int keys
, int attachment
)
1292 if ((m_sensitivity
& OP_DRAG_RIGHT
) != OP_DRAG_RIGHT
)
1298 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1299 m_parent
->GetEventHandler()->OnEndDragRight(x
, y
, keys
, attachment
);
1305 void wxShape::OnDrawOutline(wxDC
& dc
, float x
, float y
, float w
, float h
)
1307 float top_left_x
= (float)(x
- w
/2.0);
1308 float top_left_y
= (float)(y
- h
/2.0);
1309 float top_right_x
= (float)(top_left_x
+ w
);
1310 float top_right_y
= (float)top_left_y
;
1311 float bottom_left_x
= (float)top_left_x
;
1312 float bottom_left_y
= (float)(top_left_y
+ h
);
1313 float bottom_right_x
= (float)top_right_x
;
1314 float bottom_right_y
= (float)bottom_left_y
;
1317 points
[0].x
= top_left_x
; points
[0].y
= top_left_y
;
1318 points
[1].x
= top_right_x
; points
[1].y
= top_right_y
;
1319 points
[2].x
= bottom_right_x
; points
[2].y
= bottom_right_y
;
1320 points
[3].x
= bottom_left_x
; points
[3].y
= bottom_left_y
;
1321 points
[4].x
= top_left_x
; points
[4].y
= top_left_y
;
1323 dc
.DrawLines(5, points
);
1326 void wxShape::Attach(wxShapeCanvas
*can
)
1331 void wxShape::Detach()
1336 void wxShape::Move(wxDC
& dc
, float x
, float y
, bool display
)
1338 float old_x
= m_xpos
;
1339 float old_y
= m_ypos
;
1341 m_xpos
= x
; m_ypos
= y
;
1343 if (!GetEventHandler()->OnMovePre(dc
, x
, y
, old_x
, old_y
, display
))
1350 ResetControlPoints();
1357 GetEventHandler()->OnMovePost(dc
, x
, y
, old_x
, old_y
, display
);
1360 void wxShape::MoveLinks(wxDC
& dc
)
1362 GetEventHandler()->OnMoveLinks(dc
);
1366 void wxShape::Draw(wxDC
& dc
)
1370 GetEventHandler()->OnDraw(dc
);
1371 GetEventHandler()->OnDrawContents(dc
);
1372 GetEventHandler()->OnDrawControlPoints(dc
);
1376 void wxShape::Flash()
1380 wxClientDC
dc(GetCanvas());
1381 GetCanvas()->PrepareDC(dc
);
1383 dc
.SetLogicalFunction(wxXOR
);
1385 dc
.SetLogicalFunction(wxCOPY
);
1390 void wxShape::Show(bool show
)
1393 wxNode
*node
= m_children
.First();
1396 wxShape
*image
= (wxShape
*)node
->Data();
1398 node
= node
->Next();
1402 void wxShape::Erase(wxDC
& dc
)
1404 GetEventHandler()->OnErase(dc
);
1405 GetEventHandler()->OnEraseControlPoints(dc
);
1408 void wxShape::EraseContents(wxDC
& dc
)
1410 GetEventHandler()->OnEraseContents(dc
);
1413 void wxShape::AddText(const wxString
& string
)
1415 wxNode
*node
= m_regions
.First();
1418 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
1419 region
->ClearText();
1420 wxShapeTextLine
*new_line
=
1421 new wxShapeTextLine(0.0, 0.0, string
);
1422 region
->GetFormattedText().Append(new_line
);
1424 m_formatted
= FALSE
;
1427 void wxShape::SetSize(float x
, float y
, bool recursive
)
1429 SetAttachmentSize(x
, y
);
1430 SetDefaultRegionSize();
1433 void wxShape::SetAttachmentSize(float w
, float h
)
1437 float width
, height
;
1438 GetBoundingBoxMin(&width
, &height
);
1441 else scaleX
= w
/width
;
1444 else scaleY
= h
/height
;
1446 wxNode
*node
= m_attachmentPoints
.First();
1449 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
1450 point
->m_x
= (float)(point
->m_x
* scaleX
);
1451 point
->m_y
= (float)(point
->m_y
* scaleY
);
1452 node
= node
->Next();
1456 // Add line FROM this object
1457 void wxShape::AddLine(wxLineShape
*line
, wxShape
*other
,
1458 int attachFrom
, int attachTo
)
1460 if (!m_lines
.Member(line
))
1461 m_lines
.Append(line
);
1463 if (!other
->m_lines
.Member(line
))
1464 other
->m_lines
.Append(line
);
1466 line
->SetFrom(this);
1468 line
->SetAttachments(attachFrom
, attachTo
);
1471 void wxShape::RemoveLine(wxLineShape
*line
)
1473 if (line
->GetFrom() == this)
1474 line
->GetTo()->m_lines
.DeleteObject(line
);
1476 line
->GetFrom()->m_lines
.DeleteObject(line
);
1478 m_lines
.DeleteObject(line
);
1482 char *wxShape::GetFunctor()
1484 return "node_image";
1487 void wxShape::WritePrologAttributes(wxExpr
*clause
)
1489 clause
->AddAttributeValueString("type", GetClassInfo()->GetClassName());
1490 clause
->AddAttributeValue("id", m_id
);
1494 int penWidth
= m_pen
->GetWidth();
1495 int penStyle
= m_pen
->GetStyle();
1497 clause
->AddAttributeValue("pen_width", (long)penWidth
);
1498 if (penStyle
!= wxSOLID
)
1499 clause
->AddAttributeValue("pen_style", (long)penStyle
);
1501 wxString penColour
= wxTheColourDatabase
->FindName(m_pen
->GetColour());
1502 if ((penColour
!= "") && (penColour
!= "BLACK"))
1503 clause
->AddAttributeValueString("pen_colour", penColour
);
1508 wxString brushColour
= wxTheColourDatabase
->FindName(m_brush
->GetColour());
1510 if ((brushColour
!= "") && (brushColour
!= "WHITE"))
1511 clause
->AddAttributeValueString("brush_colour", brushColour
);
1513 if (m_brush
->GetStyle() != wxSOLID
)
1514 clause
->AddAttributeValue("brush_style", (long)m_brush
->GetStyle());
1519 int n_lines
= m_lines
.Number();
1522 wxExpr
*list
= new wxExpr(PrologList
);
1523 wxNode
*node
= m_lines
.First();
1526 wxShape
*line
= (wxShape
*)node
->Data();
1527 wxExpr
*id_expr
= new wxExpr(line
->GetId());
1528 list
->Append(id_expr
);
1529 node
= node
->Next();
1531 clause
->AddAttributeValue("arcs", list
);
1534 // Miscellaneous members
1535 if (m_attachmentMode
!= 0)
1536 clause
->AddAttributeValue("use_attachments", (long)m_attachmentMode
);
1537 if (m_sensitivity
!= OP_ALL
)
1538 clause
->AddAttributeValue("sensitivity", (long)m_sensitivity
);
1539 if (!m_spaceAttachments
)
1540 clause
->AddAttributeValue("space_attachments", (long)m_spaceAttachments
);
1542 clause
->AddAttributeValue("fixed_width", (long)m_fixedWidth
);
1544 clause
->AddAttributeValue("fixed_height", (long)m_fixedHeight
);
1545 if (m_shadowMode
!= SHADOW_NONE
)
1546 clause
->AddAttributeValue("shadow_mode", (long)m_shadowMode
);
1547 if (m_centreResize
!= TRUE
)
1548 clause
->AddAttributeValue("centre_resize", (long)0);
1549 if (m_highlighted
!= FALSE
)
1550 clause
->AddAttributeValue("hilite", (long)m_highlighted
);
1552 if (m_parent
) // For composite objects
1553 clause
->AddAttributeValue("parent", (long)m_parent
->GetId());
1555 if (m_rotation
!= 0.0)
1556 clause
->AddAttributeValue("rotation", m_rotation
);
1558 // Write user-defined attachment points, if any
1559 if (m_attachmentPoints
.Number() > 0)
1561 wxExpr
*attachmentList
= new wxExpr(PrologList
);
1562 wxNode
*node
= m_attachmentPoints
.First();
1565 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
1566 wxExpr
*pointExpr
= new wxExpr(PrologList
);
1567 pointExpr
->Append(new wxExpr((long)point
->m_id
));
1568 pointExpr
->Append(new wxExpr(point
->m_x
));
1569 pointExpr
->Append(new wxExpr(point
->m_y
));
1570 attachmentList
->Append(pointExpr
);
1571 node
= node
->Next();
1573 clause
->AddAttributeValue("user_attachments", attachmentList
);
1576 // Write text regions
1577 WriteRegions(clause
);
1580 void wxShape::WriteRegions(wxExpr
*clause
)
1582 // Output regions as region1 = (...), region2 = (...), etc
1583 // and formatted text as text1 = (...), text2 = (...) etc.
1585 char regionNameBuf
[20];
1586 char textNameBuf
[20];
1587 wxNode
*node
= m_regions
.First();
1590 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
1591 sprintf(regionNameBuf
, "region%d", regionNo
);
1592 sprintf(textNameBuf
, "text%d", regionNo
);
1594 // Original text and region attributes:
1595 // region1 = (regionName regionText x y width height minWidth minHeight proportionX proportionY
1596 // formatMode fontSize fontFamily fontStyle fontWeight textColour)
1597 wxExpr
*regionExpr
= new wxExpr(PrologList
);
1598 regionExpr
->Append(new wxExpr(PrologString
, (region
->m_regionName
? region
->m_regionName
: "")));
1599 regionExpr
->Append(new wxExpr(PrologString
, (region
->m_regionText
? region
->m_regionText
: "")));
1601 regionExpr
->Append(new wxExpr(region
->m_x
));
1602 regionExpr
->Append(new wxExpr(region
->m_y
));
1603 regionExpr
->Append(new wxExpr(region
->GetWidth()));
1604 regionExpr
->Append(new wxExpr(region
->GetHeight()));
1606 regionExpr
->Append(new wxExpr(region
->m_minWidth
));
1607 regionExpr
->Append(new wxExpr(region
->m_minHeight
));
1608 regionExpr
->Append(new wxExpr(region
->m_regionProportionX
));
1609 regionExpr
->Append(new wxExpr(region
->m_regionProportionY
));
1611 regionExpr
->Append(new wxExpr((long)region
->m_formatMode
));
1613 regionExpr
->Append(new wxExpr((long)(region
->m_font
? region
->m_font
->GetPointSize() : 10)));
1614 regionExpr
->Append(new wxExpr((long)(region
->m_font
? region
->m_font
->GetFamily() : wxDEFAULT
)));
1615 regionExpr
->Append(new wxExpr((long)(region
->m_font
? region
->m_font
->GetStyle() : wxDEFAULT
)));
1616 regionExpr
->Append(new wxExpr((long)(region
->m_font
? region
->m_font
->GetWeight() : wxNORMAL
)));
1617 regionExpr
->Append(new wxExpr(PrologString
, region
->m_textColour
? region
->m_textColour
: "BLACK"));
1619 // New members for pen colour/style
1620 regionExpr
->Append(new wxExpr(PrologString
, region
->m_penColour
? region
->m_penColour
: "BLACK"));
1621 regionExpr
->Append(new wxExpr((long)region
->m_penStyle
));
1624 // text1 = ((x y string) (x y string) ...)
1625 wxExpr
*textExpr
= new wxExpr(PrologList
);
1627 wxNode
*textNode
= region
->m_formattedText
.First();
1630 wxShapeTextLine
*line
= (wxShapeTextLine
*)textNode
->Data();
1631 wxExpr
*list2
= new wxExpr(PrologList
);
1632 list2
->Append(new wxExpr(line
->GetX()));
1633 list2
->Append(new wxExpr(line
->GetY()));
1634 list2
->Append(new wxExpr(PrologString
, line
->GetText()));
1635 textExpr
->Append(list2
);
1636 textNode
= textNode
->Next();
1639 // Now add both attributes to the clause
1640 clause
->AddAttributeValue(regionNameBuf
, regionExpr
);
1641 clause
->AddAttributeValue(textNameBuf
, textExpr
);
1643 node
= node
->Next();
1648 void wxShape::ReadPrologAttributes(wxExpr
*clause
)
1650 clause
->GetAttributeValue("id", m_id
);
1653 clause
->GetAttributeValue("x", m_xpos
);
1654 clause
->GetAttributeValue("y", m_ypos
);
1656 // Input text strings (FOR COMPATIBILITY WITH OLD FILES ONLY. SEE REGION CODE BELOW.)
1658 wxExpr
*strings
= clause
->AttributeValue("text");
1659 if (strings
&& strings
->Type() == PrologList
)
1661 m_formatted
= TRUE
; // Assume text is formatted unless we prove otherwise
1662 wxExpr
*node
= strings
->value
.first
;
1665 wxExpr
*string_expr
= node
;
1668 wxString
the_string("");
1670 // string_expr can either be a string, or a list of
1671 // 3 elements: x, y, and string.
1672 if (string_expr
->Type() == PrologString
)
1674 the_string
= string_expr
->StringValue();
1675 m_formatted
= FALSE
;
1677 else if (string_expr
->Type() == PrologList
)
1679 wxExpr
*first
= string_expr
->value
.first
;
1680 wxExpr
*second
= first
? first
->next
: NULL
;
1681 wxExpr
*third
= second
? second
->next
: NULL
;
1683 if (first
&& second
&& third
&&
1684 (first
->Type() == PrologReal
|| first
->Type() == PrologInteger
) &&
1685 (second
->Type() == PrologReal
|| second
->Type() == PrologInteger
) &&
1686 third
->Type() == PrologString
)
1688 if (first
->Type() == PrologReal
)
1689 the_x
= first
->RealValue();
1690 else the_x
= (float)first
->IntegerValue();
1692 if (second
->Type() == PrologReal
)
1693 the_y
= second
->RealValue();
1694 else the_y
= (float)second
->IntegerValue();
1696 the_string
= third
->StringValue();
1699 wxShapeTextLine
*line
=
1700 new wxShapeTextLine(the_x
, the_y
, (char*) (const char*) the_string
);
1701 m_text
.Append(line
);
1707 wxString pen_string
= "";
1708 wxString brush_string
= "";
1710 int pen_style
= wxSOLID
;
1711 int brush_style
= wxSOLID
;
1712 m_attachmentMode
= FALSE
;
1714 clause
->GetAttributeValue("pen_colour", pen_string
);
1715 clause
->GetAttributeValue("text_colour", m_textColourName
);
1717 SetTextColour(m_textColourName
);
1719 clause
->GetAttributeValue("region_name", m_regionName
);
1721 clause
->GetAttributeValue("brush_colour", brush_string
);
1722 clause
->GetAttributeValue("pen_width", pen_width
);
1723 clause
->GetAttributeValue("pen_style", pen_style
);
1724 clause
->GetAttributeValue("brush_style", brush_style
);
1726 int iVal
= (int) m_attachmentMode
;
1727 clause
->GetAttributeValue("use_attachments", iVal
);
1728 m_attachmentMode
= (iVal
!= 0);
1730 clause
->GetAttributeValue("sensitivity", m_sensitivity
);
1732 iVal
= (int) m_spaceAttachments
;
1733 clause
->GetAttributeValue("space_attachments", iVal
);
1734 m_spaceAttachments
= (iVal
!= 0);
1736 iVal
= (int) m_fixedWidth
;
1737 clause
->GetAttributeValue("fixed_width", iVal
);
1738 m_fixedWidth
= (iVal
!= 0);
1740 iVal
= (int) m_fixedHeight
;
1741 clause
->GetAttributeValue("fixed_height", iVal
);
1742 m_fixedHeight
= (iVal
!= 0);
1744 clause
->GetAttributeValue("format_mode", m_formatMode
);
1745 clause
->GetAttributeValue("shadow_mode", m_shadowMode
);
1747 iVal
= (int) m_centreResize
;
1748 clause
->GetAttributeValue("centre_resize", iVal
);
1749 m_centreResize
= (iVal
!= 0);
1751 iVal
= (int) m_highlighted
;
1752 clause
->GetAttributeValue("hilite", iVal
);
1753 m_highlighted
= (iVal
!= 0);
1755 clause
->GetAttributeValue("rotation", m_rotation
);
1757 if (pen_string
== "")
1758 pen_string
= "BLACK";
1759 if (brush_string
== "")
1760 brush_string
= "WHITE";
1762 m_pen
= wxThePenList
->FindOrCreatePen(pen_string
, pen_width
, pen_style
);
1764 m_pen
= wxBLACK_PEN
;
1766 m_brush
= wxTheBrushList
->FindOrCreateBrush(brush_string
, brush_style
);
1768 m_brush
= wxWHITE_BRUSH
;
1770 int point_size
= 10;
1771 clause
->GetAttributeValue("point_size", point_size
);
1772 SetFont(MatchFont(point_size
));
1774 // Read user-defined attachment points, if any
1775 wxExpr
*attachmentList
= clause
->AttributeValue("user_attachments");
1778 wxExpr
*pointExpr
= attachmentList
->GetFirst();
1781 wxExpr
*idExpr
= pointExpr
->Nth(0);
1782 wxExpr
*xExpr
= pointExpr
->Nth(1);
1783 wxExpr
*yExpr
= pointExpr
->Nth(2);
1784 if (idExpr
&& xExpr
&& yExpr
)
1786 wxAttachmentPoint
*point
= new wxAttachmentPoint
;
1787 point
->m_id
= (int)idExpr
->IntegerValue();
1788 point
->m_x
= xExpr
->RealValue();
1789 point
->m_y
= yExpr
->RealValue();
1790 m_attachmentPoints
.Append((wxObject
*)point
);
1792 pointExpr
= pointExpr
->GetNext();
1796 // Read text regions
1797 ReadRegions(clause
);
1800 void wxShape::ReadRegions(wxExpr
*clause
)
1804 // region1 = (regionName regionText x y width height minWidth minHeight proportionX proportionY
1805 // formatMode fontSize fontFamily fontStyle fontWeight textColour)
1807 char regionNameBuf
[20];
1808 char textNameBuf
[20];
1810 wxExpr
*regionExpr
= NULL
;
1811 wxExpr
*textExpr
= NULL
;
1812 sprintf(regionNameBuf
, "region%d", regionNo
);
1813 sprintf(textNameBuf
, "text%d", regionNo
);
1815 m_formatted
= TRUE
; // Assume text is formatted unless we prove otherwise
1817 while (regionExpr
= clause
->AttributeValue(regionNameBuf
))
1820 * Get the region information
1824 wxString
regionName("");
1825 wxString
regionText("");
1830 float minWidth
= 5.0;
1831 float minHeight
= 5.0;
1832 float m_regionProportionX
= -1.0;
1833 float m_regionProportionY
= -1.0;
1834 int formatMode
= FORMAT_NONE
;
1836 int fontFamily
= wxSWISS
;
1837 int fontStyle
= wxNORMAL
;
1838 int fontWeight
= wxNORMAL
;
1839 wxString
regionTextColour("");
1840 wxString
penColour("");
1841 int penStyle
= wxSOLID
;
1843 if (regionExpr
->Type() == PrologList
)
1845 wxExpr
*nameExpr
= regionExpr
->Nth(0);
1846 wxExpr
*textExpr
= regionExpr
->Nth(1);
1847 wxExpr
*xExpr
= regionExpr
->Nth(2);
1848 wxExpr
*yExpr
= regionExpr
->Nth(3);
1849 wxExpr
*widthExpr
= regionExpr
->Nth(4);
1850 wxExpr
*heightExpr
= regionExpr
->Nth(5);
1851 wxExpr
*minWidthExpr
= regionExpr
->Nth(6);
1852 wxExpr
*minHeightExpr
= regionExpr
->Nth(7);
1853 wxExpr
*propXExpr
= regionExpr
->Nth(8);
1854 wxExpr
*propYExpr
= regionExpr
->Nth(9);
1855 wxExpr
*formatExpr
= regionExpr
->Nth(10);
1856 wxExpr
*sizeExpr
= regionExpr
->Nth(11);
1857 wxExpr
*familyExpr
= regionExpr
->Nth(12);
1858 wxExpr
*styleExpr
= regionExpr
->Nth(13);
1859 wxExpr
*weightExpr
= regionExpr
->Nth(14);
1860 wxExpr
*colourExpr
= regionExpr
->Nth(15);
1861 wxExpr
*penColourExpr
= regionExpr
->Nth(16);
1862 wxExpr
*penStyleExpr
= regionExpr
->Nth(17);
1864 regionName
= nameExpr
->StringValue();
1865 regionText
= textExpr
->StringValue();
1867 x
= xExpr
->RealValue();
1868 y
= yExpr
->RealValue();
1870 width
= widthExpr
->RealValue();
1871 height
= heightExpr
->RealValue();
1873 minWidth
= minWidthExpr
->RealValue();
1874 minHeight
= minHeightExpr
->RealValue();
1876 m_regionProportionX
= propXExpr
->RealValue();
1877 m_regionProportionY
= propYExpr
->RealValue();
1879 formatMode
= (formatExpr
->IntegerValue() != 0);
1880 fontSize
= (int)sizeExpr
->IntegerValue();
1881 fontFamily
= (int)familyExpr
->IntegerValue();
1882 fontStyle
= (int)styleExpr
->IntegerValue();
1883 fontWeight
= (int)weightExpr
->IntegerValue();
1887 regionTextColour
= colourExpr
->StringValue();
1890 regionTextColour
= "BLACK";
1893 penColour
= penColourExpr
->StringValue();
1895 penStyle
= (int)penStyleExpr
->IntegerValue();
1897 wxFont
*font
= wxTheFontList
->FindOrCreateFont(fontSize
, fontFamily
, fontStyle
, fontWeight
);
1899 wxShapeRegion
*region
= new wxShapeRegion
;
1900 region
->SetProportions(m_regionProportionX
, m_regionProportionY
);
1901 region
->SetFont(font
);
1902 region
->SetSize(width
, height
);
1903 region
->SetPosition(x
, y
);
1904 region
->SetMinSize(minWidth
, minHeight
);
1905 region
->SetFormatMode(formatMode
);
1906 region
->SetPenStyle(penStyle
);
1907 if (penColour
!= "")
1908 region
->SetPenColour(penColour
);
1910 region
->m_textColour
= regionTextColour
;
1911 region
->m_regionText
= regionText
;
1912 region
->m_regionName
= regionName
;
1914 m_regions
.Append(region
);
1917 * Get the formatted text strings
1920 textExpr
= clause
->AttributeValue(textNameBuf
);
1921 if (textExpr
&& (textExpr
->Type() == PrologList
))
1923 wxExpr
*node
= textExpr
->value
.first
;
1926 wxExpr
*string_expr
= node
;
1929 wxString
the_string("");
1931 // string_expr can either be a string, or a list of
1932 // 3 elements: x, y, and string.
1933 if (string_expr
->Type() == PrologString
)
1935 the_string
= string_expr
->StringValue();
1936 m_formatted
= FALSE
;
1938 else if (string_expr
->Type() == PrologList
)
1940 wxExpr
*first
= string_expr
->value
.first
;
1941 wxExpr
*second
= first
? first
->next
: NULL
;
1942 wxExpr
*third
= second
? second
->next
: NULL
;
1944 if (first
&& second
&& third
&&
1945 (first
->Type() == PrologReal
|| first
->Type() == PrologInteger
) &&
1946 (second
->Type() == PrologReal
|| second
->Type() == PrologInteger
) &&
1947 third
->Type() == PrologString
)
1949 if (first
->Type() == PrologReal
)
1950 the_x
= first
->RealValue();
1951 else the_x
= (float)first
->IntegerValue();
1953 if (second
->Type() == PrologReal
)
1954 the_y
= second
->RealValue();
1955 else the_y
= (float)second
->IntegerValue();
1957 the_string
= third
->StringValue();
1962 wxShapeTextLine
*line
=
1963 new wxShapeTextLine(the_x
, the_y
, (char*) (const char*) the_string
);
1964 region
->m_formattedText
.Append(line
);
1971 sprintf(regionNameBuf
, "region%d", regionNo
);
1972 sprintf(textNameBuf
, "text%d", regionNo
);
1975 // Compatibility: check for no regions (old file).
1976 // Lines and divided rectangles must deal with this compatibility
1977 // theirselves. Composites _may_ not have any regions anyway.
1978 if ((m_regions
.Number() == 0) &&
1979 !this->IsKindOf(CLASSINFO(wxLineShape
)) && !this->IsKindOf(CLASSINFO(wxDividedShape
)) &&
1980 !this->IsKindOf(CLASSINFO(wxCompositeShape
)))
1982 wxShapeRegion
*newRegion
= new wxShapeRegion
;
1983 newRegion
->SetName("0");
1984 m_regions
.Append((wxObject
*)newRegion
);
1985 if (m_text
.Number() > 0)
1987 newRegion
->ClearText();
1988 wxNode
*node
= m_text
.First();
1991 wxShapeTextLine
*textLine
= (wxShapeTextLine
*)node
->Data();
1992 wxNode
*next
= node
->Next();
1993 newRegion
->GetFormattedText().Append((wxObject
*)textLine
);
2003 void wxShape::Copy(wxShape
& copy
)
2005 copy
.m_xpos
= m_xpos
;
2006 copy
.m_ypos
= m_ypos
;
2008 copy
.m_brush
= m_brush
;
2009 copy
.m_textColour
= m_textColour
;
2010 copy
.m_centreResize
= m_centreResize
;
2011 copy
.m_attachmentMode
= m_attachmentMode
;
2012 copy
.m_spaceAttachments
= m_spaceAttachments
;
2013 copy
.m_highlighted
= m_highlighted
;
2014 copy
.m_rotation
= m_rotation
;
2015 copy
.m_textColourName
= m_textColourName
;
2016 copy
.m_regionName
= m_regionName
;
2018 copy
.m_sensitivity
= m_sensitivity
;
2019 copy
.m_draggable
= m_draggable
;
2020 copy
.m_fixedWidth
= m_fixedWidth
;
2021 copy
.m_fixedHeight
= m_fixedHeight
;
2022 copy
.m_formatMode
= m_formatMode
;
2023 copy
.m_drawHandles
= m_drawHandles
;
2025 copy
.m_visible
= m_visible
;
2026 copy
.m_shadowMode
= m_shadowMode
;
2027 copy
.m_shadowOffsetX
= m_shadowOffsetX
;
2028 copy
.m_shadowOffsetY
= m_shadowOffsetY
;
2029 copy
.m_shadowBrush
= m_shadowBrush
;
2031 // Copy text regions
2032 copy
.ClearRegions();
2033 wxNode
*node
= m_regions
.First();
2036 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
2037 wxShapeRegion
*newRegion
= new wxShapeRegion(*region
);
2038 copy
.m_regions
.Append(newRegion
);
2039 node
= node
->Next();
2043 copy
.ClearAttachments();
2044 node
= m_attachmentPoints
.First();
2047 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
2048 wxAttachmentPoint
*newPoint
= new wxAttachmentPoint
;
2049 newPoint
->m_id
= point
->m_id
;
2050 newPoint
->m_x
= point
->m_x
;
2051 newPoint
->m_y
= point
->m_y
;
2052 copy
.m_attachmentPoints
.Append((wxObject
*)newPoint
);
2053 node
= node
->Next();
2057 // Create and return a new, fully copied object.
2058 wxShape
*wxShape::CreateNewCopy(wxShapeCanvas
*theCanvas
)
2060 wxObjectCopyMapping
.Clear();
2061 wxShape
*newObject
= PrivateCopy();
2063 newObject
->AddToCanvas(theCanvas
);
2064 newObject
->Recompute();
2068 // Default - make 6 control points
2069 void wxShape::MakeControlPoints()
2071 float maxX
, maxY
, minX
, minY
;
2073 GetBoundingBoxMax(&maxX
, &maxY
);
2074 GetBoundingBoxMin(&minX
, &minY
);
2076 float widthMin
= (float)(minX
+ CONTROL_POINT_SIZE
+ 2);
2077 float heightMin
= (float)(minY
+ CONTROL_POINT_SIZE
+ 2);
2079 // Offsets from main object
2080 float top
= (float)(- (heightMin
/ 2.0));
2081 float bottom
= (float)(heightMin
/ 2.0 + (maxY
- minY
));
2082 float left
= (float)(- (widthMin
/ 2.0));
2083 float right
= (float)(widthMin
/ 2.0 + (maxX
- minX
));
2085 wxControlPoint
*control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, left
, top
,
2086 CONTROL_POINT_DIAGONAL
);
2087 m_canvas
->AddShape(control
);
2088 m_controlPoints
.Append(control
);
2090 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, 0, top
,
2091 CONTROL_POINT_VERTICAL
);
2092 m_canvas
->AddShape(control
);
2093 m_controlPoints
.Append(control
);
2095 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, right
, top
,
2096 CONTROL_POINT_DIAGONAL
);
2097 m_canvas
->AddShape(control
);
2098 m_controlPoints
.Append(control
);
2100 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, right
, 0,
2101 CONTROL_POINT_HORIZONTAL
);
2102 m_canvas
->AddShape(control
);
2103 m_controlPoints
.Append(control
);
2105 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, right
, bottom
,
2106 CONTROL_POINT_DIAGONAL
);
2107 m_canvas
->AddShape(control
);
2108 m_controlPoints
.Append(control
);
2110 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, 0, bottom
,
2111 CONTROL_POINT_VERTICAL
);
2112 m_canvas
->AddShape(control
);
2113 m_controlPoints
.Append(control
);
2115 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, left
, bottom
,
2116 CONTROL_POINT_DIAGONAL
);
2117 m_canvas
->AddShape(control
);
2118 m_controlPoints
.Append(control
);
2120 control
= new wxControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, left
, 0,
2121 CONTROL_POINT_HORIZONTAL
);
2122 m_canvas
->AddShape(control
);
2123 m_controlPoints
.Append(control
);
2127 void wxShape::MakeMandatoryControlPoints()
2129 wxNode
*node
= m_children
.First();
2132 wxShape
*child
= (wxShape
*)node
->Data();
2133 child
->MakeMandatoryControlPoints();
2134 node
= node
->Next();
2138 void wxShape::ResetMandatoryControlPoints()
2140 wxNode
*node
= m_children
.First();
2143 wxShape
*child
= (wxShape
*)node
->Data();
2144 child
->ResetMandatoryControlPoints();
2145 node
= node
->Next();
2149 void wxShape::ResetControlPoints()
2151 ResetMandatoryControlPoints();
2153 if (m_controlPoints
.Number() < 1)
2156 float maxX
, maxY
, minX
, minY
;
2158 GetBoundingBoxMax(&maxX
, &maxY
);
2159 GetBoundingBoxMin(&minX
, &minY
);
2161 float widthMin
= (float)(minX
+ CONTROL_POINT_SIZE
+ 2);
2162 float heightMin
= (float)(minY
+ CONTROL_POINT_SIZE
+ 2);
2164 // Offsets from main object
2165 float top
= (float)(- (heightMin
/ 2.0));
2166 float bottom
= (float)(heightMin
/ 2.0 + (maxY
- minY
));
2167 float left
= (float)(- (widthMin
/ 2.0));
2168 float right
= (float)(widthMin
/ 2.0 + (maxX
- minX
));
2170 wxNode
*node
= m_controlPoints
.First();
2171 wxControlPoint
*control
= (wxControlPoint
*)node
->Data();
2172 control
->m_xoffset
= left
; control
->m_yoffset
= top
;
2174 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2175 control
->m_xoffset
= 0; control
->m_yoffset
= top
;
2177 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2178 control
->m_xoffset
= right
; control
->m_yoffset
= top
;
2180 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2181 control
->m_xoffset
= right
; control
->m_yoffset
= 0;
2183 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2184 control
->m_xoffset
= right
; control
->m_yoffset
= bottom
;
2186 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2187 control
->m_xoffset
= 0; control
->m_yoffset
= bottom
;
2189 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2190 control
->m_xoffset
= left
; control
->m_yoffset
= bottom
;
2192 node
= node
->Next(); control
= (wxControlPoint
*)node
->Data();
2193 control
->m_xoffset
= left
; control
->m_yoffset
= 0;
2196 void wxShape::DeleteControlPoints(wxDC
*dc
)
2198 wxNode
*node
= m_controlPoints
.First();
2201 wxControlPoint
*control
= (wxControlPoint
*)node
->Data();
2203 control
->GetEventHandler()->OnErase(*dc
);
2204 m_canvas
->RemoveShape(control
);
2207 node
= m_controlPoints
.First();
2209 // Children of divisions are contained objects,
2211 if (!IsKindOf(CLASSINFO(wxDivisionShape
)))
2213 node
= m_children
.First();
2216 wxShape
*child
= (wxShape
*)node
->Data();
2217 child
->DeleteControlPoints(dc
);
2218 node
= node
->Next();
2223 void wxShape::OnDrawControlPoints(wxDC
& dc
)
2228 dc
.SetBrush(wxBLACK_BRUSH
);
2229 dc
.SetPen(wxBLACK_PEN
);
2231 wxNode
*node
= m_controlPoints
.First();
2234 wxControlPoint
*control
= (wxControlPoint
*)node
->Data();
2236 node
= node
->Next();
2238 // Children of divisions are contained objects,
2240 // This test bypasses the type facility for speed
2241 // (critical when drawing)
2242 if (!IsKindOf(CLASSINFO(wxDivisionShape
)))
2244 node
= m_children
.First();
2247 wxShape
*child
= (wxShape
*)node
->Data();
2248 child
->GetEventHandler()->OnDrawControlPoints(dc
);
2249 node
= node
->Next();
2254 void wxShape::OnEraseControlPoints(wxDC
& dc
)
2256 wxNode
*node
= m_controlPoints
.First();
2259 wxControlPoint
*control
= (wxControlPoint
*)node
->Data();
2261 node
= node
->Next();
2263 if (!IsKindOf(CLASSINFO(wxDivisionShape
)))
2265 node
= m_children
.First();
2268 wxShape
*child
= (wxShape
*)node
->Data();
2269 child
->GetEventHandler()->OnEraseControlPoints(dc
);
2270 node
= node
->Next();
2275 void wxShape::Select(bool select
, wxDC
* dc
)
2277 m_selected
= select
;
2280 MakeControlPoints();
2281 // Children of divisions are contained objects,
2283 if (!IsKindOf(CLASSINFO(wxDivisionShape
)))
2285 wxNode
*node
= m_children
.First();
2288 wxShape
*child
= (wxShape
*)node
->Data();
2289 child
->MakeMandatoryControlPoints();
2290 node
= node
->Next();
2294 GetEventHandler()->OnDrawControlPoints(*dc
);
2298 DeleteControlPoints(dc
);
2299 if (!IsKindOf(CLASSINFO(wxDivisionShape
)))
2301 wxNode
*node
= m_children
.First();
2304 wxShape
*child
= (wxShape
*)node
->Data();
2305 child
->DeleteControlPoints(dc
);
2306 node
= node
->Next();
2312 bool wxShape::Selected() const
2317 bool wxShape::AncestorSelected() const
2319 if (m_selected
) return TRUE
;
2323 return GetParent()->AncestorSelected();
2326 int wxShape::GetNumberOfAttachments()
2328 // Should return the MAXIMUM attachment point id here,
2329 // so higher-level functions can iterate through all attachments,
2330 // even if they're not contiguous.
2331 if (m_attachmentPoints
.Number() == 0)
2336 wxNode
*node
= m_attachmentPoints
.First();
2339 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
2340 if (point
->m_id
> maxN
)
2342 node
= node
->Next();
2348 bool wxShape::AttachmentIsValid(int attachment
)
2350 if ((attachment
>= 0) && (attachment
< 4))
2353 wxNode
*node
= m_attachmentPoints
.First();
2356 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
2357 if (point
->m_id
== attachment
)
2359 node
= node
->Next();
2364 bool wxShape::GetAttachmentPosition(int attachment
, float *x
, float *y
,
2365 int nth
, int no_arcs
, wxLineShape
*line
)
2367 if (!m_attachmentMode
)
2369 *x
= m_xpos
; *y
= m_ypos
;
2374 wxNode
*node
= m_attachmentPoints
.First();
2377 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
2378 if (point
->m_id
== attachment
)
2380 *x
= (float)(m_xpos
+ point
->m_x
);
2381 *y
= (float)(m_ypos
+ point
->m_y
);
2384 node
= node
->Next();
2386 *x
= m_xpos
; *y
= m_ypos
;
2391 void wxShape::GetBoundingBoxMax(float *w
, float *h
)
2394 GetBoundingBoxMin(&ww
, &hh
);
2395 if (m_shadowMode
!= SHADOW_NONE
)
2397 ww
+= m_shadowOffsetX
;
2398 hh
+= m_shadowOffsetY
;
2404 // Returns TRUE if image is a descendant of this composite
2405 bool wxShape::HasDescendant(wxShape
*image
)
2409 wxNode
*node
= m_children
.First();
2412 wxShape
*child
= (wxShape
*)node
->Data();
2413 bool ans
= child
->HasDescendant(image
);
2416 node
= node
->Next();
2421 // Clears points from a list of wxRealPoints, and clears list
2422 void wxShape::ClearPointList(wxList
& list
)
2424 wxNode
* node
= list
.First();
2427 wxRealPoint
* pt
= (wxRealPoint
*) node
->Data();
2430 node
= node
->Next();