]> git.saurik.com Git - wxWidgets.git/blobdiff - utils/ogl/src/basic.cpp
Added test for sprintf and vsnprintf to fix string.cpp for non-GNU systems.
[wxWidgets.git] / utils / ogl / src / basic.cpp
index 1e366c9f339ed1590ed4496d7f66d6b89e4230bb..4faa13292579f860bb6060cc25c8bf65a642099c 100644 (file)
 #include <wx/wx.h>
 #endif
 
-#ifdef PROLOGIO
 #include <wx/wxexpr.h>
-#endif
 
-#if USE_IOSTREAMH
+#if wxUSE_IOSTREAMH
 #include <iostream.h>
 #else
 #include <iostream>
@@ -127,6 +125,12 @@ void wxShapeEvtHandler::OnDrawContents(wxDC& dc)
     m_previousHandler->OnDrawContents(dc);
 }
 
+void wxShapeEvtHandler::OnDrawBranches(wxDC& dc, bool erase)
+{
+  if (m_previousHandler)
+    m_previousHandler->OnDrawBranches(dc, erase);
+}
+
 void wxShapeEvtHandler::OnSize(double x, double y)
 {
   if (m_previousHandler)
@@ -171,6 +175,12 @@ void wxShapeEvtHandler::OnLeftClick(double x, double y, int keys, int attachment
     m_previousHandler->OnLeftClick(x, y, keys, attachment);
 }
 
+void wxShapeEvtHandler::OnLeftDoubleClick(double x, double y, int keys, int attachment)
+{
+  if (m_previousHandler)
+    m_previousHandler->OnLeftDoubleClick(x, y, keys, attachment);
+}
+
 void wxShapeEvtHandler::OnRightClick(double x, double y, int keys, int attachment)
 {
   if (m_previousHandler)
@@ -276,7 +286,7 @@ wxShape::wxShape(wxShapeCanvas *can)
   m_visible = FALSE;
   m_clientData = NULL;
   m_selected = FALSE;
-  m_attachmentMode = FALSE;
+  m_attachmentMode = ATTACHMENT_MODE_NONE;
   m_spaceAttachments = TRUE;
   m_disableLabel = FALSE;
   m_fixedWidth = FALSE;
@@ -287,15 +297,20 @@ wxShape::wxShape(wxShapeCanvas *can)
   m_parent = NULL;
   m_formatMode = FORMAT_CENTRE_HORIZ | FORMAT_CENTRE_VERT;
   m_shadowMode = SHADOW_NONE;
-  m_shadowOffsetX = 6.0;
-  m_shadowOffsetY = 6.0;
+  m_shadowOffsetX = 6;
+  m_shadowOffsetY = 6;
   m_shadowBrush = wxBLACK_BRUSH;
-  m_textMarginX = 5.0;
-  m_textMarginY = 5.0;
+  m_textMarginX = 5;
+  m_textMarginY = 5;
   m_regionName = "0";
   m_centreResize = TRUE;
+  m_maintainAspectRatio = FALSE;
   m_highlighted = FALSE;
   m_rotation = 0.0;
+  m_branchNeckLength = 10;
+  m_branchStemLength = 10;
+  m_branchSpacing = 10;
+  m_branchStyle = BRANCHING_ATTACHMENT_NORMAL;
 
   // Set up a default region. Much of the above will be put into
   // the region eventually (the duplication is for compatibility)
@@ -540,7 +555,6 @@ bool wxShape::HitTest(double x, double y, int *attachment, double *distance)
 
   int nearest_attachment = 0;
 
-
   // If within the bounding box, check the attachment points
   // within the object.
 
@@ -549,10 +563,13 @@ bool wxShape::HitTest(double x, double y, int *attachment, double *distance)
     int n = GetNumberOfAttachments();
     double nearest = 999999.0;
 
+    // GetAttachmentPosition[Edge] takes a logical attachment position,
+    // i.e. if it's rotated through 90%, position 0 is East-facing.
+
     for (int i = 0; i < n; i++)
     {
       double xp, yp;
-      if (GetAttachmentPosition(i, &xp, &yp))
+      if (GetAttachmentPositionEdge(i, &xp, &yp))
       {
         double l = (double)sqrt(((xp - x) * (xp - x)) +
                    ((yp - y) * (yp - y)));
@@ -1037,7 +1054,8 @@ void wxShape::DrawLinks(wxDC& dc, int attachment, bool recurse)
 // This is the default, rectangular implementation.
 bool wxShape::AttachmentSortTest(int attachmentPoint, const wxRealPoint& pt1, const wxRealPoint& pt2)
 {
-    switch (attachmentPoint)
+    int physicalAttachment = LogicalToPhysicalAttachment(attachmentPoint);
+    switch (physicalAttachment)
     {
         case 0:
         case 2:
@@ -1059,7 +1077,7 @@ bool wxShape::AttachmentSortTest(int attachmentPoint, const wxRealPoint& pt1, co
 bool wxShape::MoveLineToNewAttachment(wxDC& dc, wxLineShape *to_move,
                                        double x, double y)
 {
-  if (!GetAttachmentMode())
+  if (GetAttachmentMode() == ATTACHMENT_MODE_NONE)
       return FALSE;
 
   int newAttachment, oldAttachment;
@@ -1501,6 +1519,7 @@ void wxShape::Draw(wxDC& dc)
     GetEventHandler()->OnDraw(dc);
     GetEventHandler()->OnDrawContents(dc);
     GetEventHandler()->OnDrawControlPoints(dc);
+    GetEventHandler()->OnDrawBranches(dc);
   }
 }
 
@@ -1534,6 +1553,7 @@ void wxShape::Erase(wxDC& dc)
 {
   GetEventHandler()->OnErase(dc);
   GetEventHandler()->OnEraseControlPoints(dc);
+  GetEventHandler()->OnDrawBranches(dc, TRUE);
 }
 
 void wxShape::EraseContents(wxDC& dc)
@@ -1590,6 +1610,43 @@ void wxShape::AddLine(wxLineShape *line, wxShape *other,
                             // The line ordering
                             int positionFrom, int positionTo)
 {
+    if (positionFrom == -1)
+    {
+        if (!m_lines.Member(line))
+            m_lines.Append(line);
+    }
+    else
+    {
+        // Don't preserve old ordering if we have new ordering instructions
+        m_lines.DeleteObject(line);
+        if (positionFrom < m_lines.Number())
+        {
+            wxNode* node = m_lines.Nth(positionFrom);
+            m_lines.Insert(node, line);
+        }
+        else
+            m_lines.Append(line);
+    }
+
+    if (positionTo == -1)
+    {
+        if (!other->m_lines.Member(line))
+            other->m_lines.Append(line);
+    }
+    else
+    {
+        // Don't preserve old ordering if we have new ordering instructions
+        other->m_lines.DeleteObject(line);
+        if (positionTo < other->m_lines.Number())
+        {
+            wxNode* node = other->m_lines.Nth(positionTo);
+            other->m_lines.Insert(node, line);
+        }
+        else
+            other->m_lines.Append(line);
+    }
+#if 0
+    // Wrong: doesn't preserve ordering of shape already linked
     m_lines.DeleteObject(line);
     other->m_lines.DeleteObject(line);
 
@@ -1618,6 +1675,7 @@ void wxShape::AddLine(wxLineShape *line, wxShape *other,
         else
             other->m_lines.Append(line);
     }
+#endif
 
     line->SetFrom(this);
     line->SetTo(other);
@@ -1682,7 +1740,7 @@ void wxShape::WriteAttributes(wxExpr *clause)
   int n_lines = m_lines.Number();
   if (n_lines > 0)
   {
-    wxExpr *list = new wxExpr(PrologList);
+    wxExpr *list = new wxExpr(wxExprList);
     wxNode *node = m_lines.First();
     while (node)
     {
@@ -1709,6 +1767,7 @@ void wxShape::WriteAttributes(wxExpr *clause)
     clause->AddAttributeValue("shadow_mode", (long)m_shadowMode);
   if (m_centreResize != TRUE)
     clause->AddAttributeValue("centre_resize", (long)0);
+  clause->AddAttributeValue("maintain_aspect_ratio", (long) m_maintainAspectRatio);
   if (m_highlighted != FALSE)
     clause->AddAttributeValue("hilite", (long)m_highlighted);
 
@@ -1718,15 +1777,23 @@ void wxShape::WriteAttributes(wxExpr *clause)
   if (m_rotation != 0.0)
     clause->AddAttributeValue("rotation", m_rotation);
 
+  if (!this->IsKindOf(CLASSINFO(wxLineShape)))
+  {
+    clause->AddAttributeValue("neck_length", (long) m_branchNeckLength);
+    clause->AddAttributeValue("stem_length", (long) m_branchStemLength);
+    clause->AddAttributeValue("branch_spacing", (long) m_branchSpacing);
+    clause->AddAttributeValue("branch_style", (long) m_branchStyle);
+  }
+
   // Write user-defined attachment points, if any
   if (m_attachmentPoints.Number() > 0)
   {
-    wxExpr *attachmentList = new wxExpr(PrologList);
+    wxExpr *attachmentList = new wxExpr(wxExprList);
     wxNode *node = m_attachmentPoints.First();
     while (node)
     {
       wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
-      wxExpr *pointExpr = new wxExpr(PrologList);
+      wxExpr *pointExpr = new wxExpr(wxExprList);
       pointExpr->Append(new wxExpr((long)point->m_id));
       pointExpr->Append(new wxExpr(point->m_x));
       pointExpr->Append(new wxExpr(point->m_y));
@@ -1757,9 +1824,9 @@ void wxShape::WriteRegions(wxExpr *clause)
     // Original text and region attributes:
     // region1 = (regionName regionText x y width height minWidth minHeight proportionX proportionY
     //            formatMode fontSize fontFamily fontStyle fontWeight textColour)
-    wxExpr *regionExpr = new wxExpr(PrologList);
-    regionExpr->Append(new wxExpr(PrologString, (region->m_regionName ? region->m_regionName : "")));
-    regionExpr->Append(new wxExpr(PrologString, (region->m_regionText ? region->m_regionText : "")));
+    wxExpr *regionExpr = new wxExpr(wxExprList);
+    regionExpr->Append(new wxExpr(wxExprString, region->m_regionName));
+    regionExpr->Append(new wxExpr(wxExprString, region->m_regionText));
 
     regionExpr->Append(new wxExpr(region->m_x));
     regionExpr->Append(new wxExpr(region->m_y));
@@ -1777,24 +1844,24 @@ void wxShape::WriteRegions(wxExpr *clause)
     regionExpr->Append(new wxExpr((long)(region->m_font ? region->m_font->GetFamily() : wxDEFAULT)));
     regionExpr->Append(new wxExpr((long)(region->m_font ? region->m_font->GetStyle() : wxDEFAULT)));
     regionExpr->Append(new wxExpr((long)(region->m_font ? region->m_font->GetWeight() : wxNORMAL)));
-    regionExpr->Append(new wxExpr(PrologString, region->m_textColour ? region->m_textColour : "BLACK"));
+    regionExpr->Append(new wxExpr(wxExprString, region->m_textColour));
 
     // New members for pen colour/style
-    regionExpr->Append(new wxExpr(PrologString, region->m_penColour ? region->m_penColour : "BLACK"));
+    regionExpr->Append(new wxExpr(wxExprString, region->m_penColour));
     regionExpr->Append(new wxExpr((long)region->m_penStyle));
 
     // Formatted text:
     // text1 = ((x y string) (x y string) ...)
-    wxExpr *textExpr = new wxExpr(PrologList);
+    wxExpr *textExpr = new wxExpr(wxExprList);
 
     wxNode *textNode = region->m_formattedText.First();
     while (textNode)
     {
       wxShapeTextLine *line = (wxShapeTextLine *)textNode->Data();
-      wxExpr *list2 = new wxExpr(PrologList);
+      wxExpr *list2 = new wxExpr(wxExprList);
       list2->Append(new wxExpr(line->GetX()));
       list2->Append(new wxExpr(line->GetY()));
-      list2->Append(new wxExpr(PrologString, line->GetText()));
+      list2->Append(new wxExpr(wxExprString, line->GetText()));
       textExpr->Append(list2);
       textNode = textNode->Next();
     }
@@ -1819,7 +1886,7 @@ void wxShape::ReadAttributes(wxExpr *clause)
   // Input text strings (FOR COMPATIBILITY WITH OLD FILES ONLY. SEE REGION CODE BELOW.)
   ClearText();
   wxExpr *strings = clause->AttributeValue("text");
-  if (strings && strings->Type() == PrologList)
+  if (strings && strings->Type() == wxExprList)
   {
     m_formatted = TRUE;  // Assume text is formatted unless we prove otherwise
     wxExpr *node = strings->value.first;
@@ -1832,27 +1899,27 @@ void wxShape::ReadAttributes(wxExpr *clause)
 
       // string_expr can either be a string, or a list of
       // 3 elements: x, y, and string.
-      if (string_expr->Type() == PrologString)
+      if (string_expr->Type() == wxExprString)
       {
         the_string = string_expr->StringValue();
         m_formatted = FALSE;
       }
-      else if (string_expr->Type() == PrologList)
+      else if (string_expr->Type() == wxExprList)
       {
         wxExpr *first = string_expr->value.first;
-        wxExpr *second = first ? first->next : NULL;
-        wxExpr *third = second ? second->next : NULL;
+        wxExpr *second = first ? first->next : (wxExpr*) NULL;
+        wxExpr *third = second ? second->next : (wxExpr*) NULL;
 
         if (first && second && third &&
-            (first->Type() == PrologReal || first->Type() == PrologInteger) &&
-            (second->Type() == PrologReal || second->Type() == PrologInteger) &&
-            third->Type() == PrologString)
+            (first->Type() == wxExprReal || first->Type() == wxExprInteger) &&
+            (second->Type() == wxExprReal || second->Type() == wxExprInteger) &&
+            third->Type() == wxExprString)
           {
-            if (first->Type() == PrologReal)
+            if (first->Type() == wxExprReal)
               the_x = first->RealValue();
             else the_x = (double)first->IntegerValue();
 
-            if (second->Type() == PrologReal)
+            if (second->Type() == wxExprReal)
               the_y = second->RealValue();
             else the_y = (double)second->IntegerValue();
 
@@ -1872,7 +1939,7 @@ void wxShape::ReadAttributes(wxExpr *clause)
   int pen_width = 1;
   int pen_style = wxSOLID;
   int brush_style = wxSOLID;
-  m_attachmentMode = FALSE;
+  m_attachmentMode = ATTACHMENT_MODE_NONE;
 
   clause->GetAttributeValue("pen_colour", pen_string);
   clause->GetAttributeValue("text_colour", m_textColourName);
@@ -1888,7 +1955,7 @@ void wxShape::ReadAttributes(wxExpr *clause)
 
   int iVal = (int) m_attachmentMode;
   clause->GetAttributeValue("use_attachments", iVal);
-  m_attachmentMode = (iVal != 0);
+  m_attachmentMode = iVal;
 
   clause->GetAttributeValue("sensitivity", m_sensitivity);
 
@@ -1907,10 +1974,28 @@ void wxShape::ReadAttributes(wxExpr *clause)
   clause->GetAttributeValue("format_mode", m_formatMode);
   clause->GetAttributeValue("shadow_mode", m_shadowMode);
 
+  iVal = m_branchNeckLength;
+  clause->GetAttributeValue("neck_length", iVal);
+  m_branchNeckLength = iVal;
+
+  iVal = m_branchStemLength;
+  clause->GetAttributeValue("stem_length", iVal);
+  m_branchStemLength = iVal;
+
+  iVal = m_branchSpacing;
+  clause->GetAttributeValue("branch_spacing", iVal);
+  m_branchSpacing = iVal;
+
+  clause->GetAttributeValue("branch_style", m_branchStyle);
+
   iVal = (int) m_centreResize;
   clause->GetAttributeValue("centre_resize", iVal);
   m_centreResize = (iVal != 0);
 
+  iVal = (int) m_maintainAspectRatio;
+  clause->GetAttributeValue("maintain_aspect_ratio", iVal);
+  m_maintainAspectRatio = (iVal != 0);
+
   iVal = (int) m_highlighted;
   clause->GetAttributeValue("hilite", iVal);
   m_highlighted = (iVal != 0);
@@ -1991,7 +2076,7 @@ void wxShape::ReadRegions(wxExpr *clause)
 
   m_formatted = TRUE;  // Assume text is formatted unless we prove otherwise
 
-  while (regionExpr = clause->AttributeValue(regionNameBuf))
+  while ((regionExpr = clause->AttributeValue(regionNameBuf)))
   {
     /*
      * Get the region information
@@ -2017,7 +2102,7 @@ void wxShape::ReadRegions(wxExpr *clause)
     wxString penColour("");
     int penStyle = wxSOLID;
 
-    if (regionExpr->Type() == PrologList)
+    if (regionExpr->Type() == wxExprList)
     {
       wxExpr *nameExpr = regionExpr->Nth(0);
       wxExpr *textExpr = regionExpr->Nth(1);
@@ -2095,7 +2180,7 @@ void wxShape::ReadRegions(wxExpr *clause)
      *
      */
     textExpr = clause->AttributeValue(textNameBuf);
-    if (textExpr && (textExpr->Type() == PrologList))
+    if (textExpr && (textExpr->Type() == wxExprList))
     {
       wxExpr *node = textExpr->value.first;
       while (node)
@@ -2107,27 +2192,27 @@ void wxShape::ReadRegions(wxExpr *clause)
 
         // string_expr can either be a string, or a list of
         // 3 elements: x, y, and string.
-        if (string_expr->Type() == PrologString)
+        if (string_expr->Type() == wxExprString)
         {
           the_string = string_expr->StringValue();
           m_formatted = FALSE;
         }
-        else if (string_expr->Type() == PrologList)
+        else if (string_expr->Type() == wxExprList)
         {
           wxExpr *first = string_expr->value.first;
-          wxExpr *second = first ? first->next : NULL;
-          wxExpr *third = second ? second->next : NULL;
+          wxExpr *second = first ? first->next : (wxExpr*) NULL;
+          wxExpr *third = second ? second->next : (wxExpr*) NULL;
 
           if (first && second && third &&
-              (first->Type() == PrologReal || first->Type() == PrologInteger) &&
-              (second->Type() == PrologReal || second->Type() == PrologInteger) &&
-              third->Type() == PrologString)
+              (first->Type() == wxExprReal || first->Type() == wxExprInteger) &&
+              (second->Type() == wxExprReal || second->Type() == wxExprInteger) &&
+              third->Type() == wxExprString)
           {
-            if (first->Type() == PrologReal)
+            if (first->Type() == wxExprReal)
               the_x = first->RealValue();
             else the_x = (double)first->IntegerValue();
 
-            if (second->Type() == PrologReal)
+            if (second->Type() == wxExprReal)
               the_y = second->RealValue();
             else the_y = (double)second->IntegerValue();
 
@@ -2186,6 +2271,7 @@ void wxShape::Copy(wxShape& copy)
   copy.m_brush = m_brush;
   copy.m_textColour = m_textColour;
   copy.m_centreResize = m_centreResize;
+  copy.m_maintainAspectRatio = m_maintainAspectRatio;
   copy.m_attachmentMode = m_attachmentMode;
   copy.m_spaceAttachments = m_spaceAttachments;
   copy.m_highlighted = m_highlighted;
@@ -2206,6 +2292,10 @@ void wxShape::Copy(wxShape& copy)
   copy.m_shadowOffsetY = m_shadowOffsetY;
   copy.m_shadowBrush = m_shadowBrush;
 
+  copy.m_branchNeckLength = m_branchNeckLength;
+  copy.m_branchStemLength = m_branchStemLength;
+  copy.m_branchSpacing = m_branchSpacing;
+
   // Copy text regions
   copy.ClearRegions();
   wxNode *node = m_regions.First();
@@ -2567,8 +2657,10 @@ int wxShape::GetNumberOfAttachments() const
 
 bool wxShape::AttachmentIsValid(int attachment) const
 {
-  if ((attachment >= 0) && (attachment < 4))
-    return TRUE;
+  if (m_attachmentPoints.Number() == 0)
+  {
+    return ((attachment >= 0) && (attachment < 4)) ;
+  }
 
   wxNode *node = m_attachmentPoints.First();
   while (node)
@@ -2584,28 +2676,97 @@ bool wxShape::AttachmentIsValid(int attachment) const
 bool wxShape::GetAttachmentPosition(int attachment, double *x, double *y, 
                                          int nth, int no_arcs, wxLineShape *line)
 {
-  if (!m_attachmentMode)
-  {
-    *x = m_xpos; *y = m_ypos;
-    return TRUE;
-  }
-  else
-  {
-    wxNode *node = m_attachmentPoints.First();
-    while (node)
+    if (m_attachmentMode == ATTACHMENT_MODE_NONE)
     {
-      wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
-      if (point->m_id == attachment)
-      {
-        *x = (double)(m_xpos + point->m_x);
-        *y = (double)(m_ypos + point->m_y);
+        *x = m_xpos; *y = m_ypos;
         return TRUE;
-      }
-      node = node->Next();
     }
-    *x = m_xpos; *y = m_ypos;
+    else if (m_attachmentMode == ATTACHMENT_MODE_BRANCHING)
+    {
+        wxRealPoint pt, stemPt;
+        GetBranchingAttachmentPoint(attachment, nth, pt, stemPt);
+        *x = pt.x;
+        *y = pt.y;
+        return TRUE;
+    }
+    else if (m_attachmentMode == ATTACHMENT_MODE_EDGE)
+    {
+        if (m_attachmentPoints.Number() > 0)
+        {
+            wxNode *node = m_attachmentPoints.First();
+            while (node)
+            {
+                wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
+                if (point->m_id == attachment)
+                {
+                    *x = (double)(m_xpos + point->m_x);
+                    *y = (double)(m_ypos + point->m_y);
+                    return TRUE;
+                }
+                node = node->Next();
+            }
+            *x = m_xpos; *y = m_ypos;
+            return FALSE;
+        }
+        else
+        {
+            // Assume is rectangular
+            double w, h;
+            GetBoundingBoxMax(&w, &h);
+            double top = (double)(m_ypos + h/2.0);
+            double bottom = (double)(m_ypos - h/2.0);
+            double left = (double)(m_xpos - w/2.0);
+            double right = (double)(m_xpos + w/2.0);
+
+            bool isEnd = (line && line->IsEnd(this));
+
+            int physicalAttachment = LogicalToPhysicalAttachment(attachment);
+
+            // Simplified code
+            switch (physicalAttachment)
+            {
+                case 0:
+                {
+                    wxRealPoint pt = CalcSimpleAttachment(wxRealPoint(left, bottom), wxRealPoint(right, bottom),
+                            nth, no_arcs, line);
+
+                    *x = pt.x; *y = pt.y;
+                    break;
+                }
+                case 1:
+                {
+                    wxRealPoint pt = CalcSimpleAttachment(wxRealPoint(right, bottom), wxRealPoint(right, top),
+                            nth, no_arcs, line);
+
+                    *x = pt.x; *y = pt.y;
+                    break;
+                }
+                case 2:
+                {
+                    wxRealPoint pt = CalcSimpleAttachment(wxRealPoint(left, top), wxRealPoint(right, top),
+                            nth, no_arcs, line);
+
+                    *x = pt.x; *y = pt.y;
+                    break;
+                }
+                case 3:
+                {
+                    wxRealPoint pt = CalcSimpleAttachment(wxRealPoint(left, bottom), wxRealPoint(left, top),
+                            nth, no_arcs, line);
+
+                    *x = pt.x; *y = pt.y;
+                    break;
+                }
+                default:
+                {
+                    return FALSE;
+                    break;
+                }
+            }
+            return TRUE;
+        }
+    }
     return FALSE;
-  }
 }
 
 void wxShape::GetBoundingBoxMax(double *w, double *h)
@@ -2749,3 +2910,365 @@ int wxShape::GetLinePosition(wxLineShape* line)
     return 0;
 }
 
+//
+//             |________|
+//                 | <- root
+//                 | <- neck
+// shoulder1 ->---------<- shoulder2
+//             | | | | |
+//                      <- branching attachment point N-1
+
+// This function gets information about where branching connections go.
+// Returns FALSE if there are no lines at this attachment.
+bool wxShape::GetBranchingAttachmentInfo(int attachment, wxRealPoint& root, wxRealPoint& neck,
+    wxRealPoint& shoulder1, wxRealPoint& shoulder2)
+{
+    int physicalAttachment = LogicalToPhysicalAttachment(attachment);
+
+    // Number of lines at this attachment.
+    int lineCount = GetAttachmentLineCount(attachment);
+
+    if (lineCount == 0)
+        return FALSE;
+
+    int totalBranchLength = m_branchSpacing * (lineCount - 1);
+
+    root = GetBranchingAttachmentRoot(attachment);
+
+    // Assume that we have attachment points 0 to 3: top, right, bottom, left.
+    switch (physicalAttachment)
+    {
+        case 0:
+        {
+            neck.x = GetX();
+            neck.y = root.y - m_branchNeckLength;
+
+            shoulder1.x = root.x - (totalBranchLength/2.0) ;
+            shoulder2.x = root.x + (totalBranchLength/2.0) ;
+
+            shoulder1.y = neck.y;
+            shoulder2.y = neck.y;
+            break;
+        }
+        case 1:
+        {
+            neck.x = root.x + m_branchNeckLength;
+            neck.y = root.y;
+
+            shoulder1.x = neck.x ;
+            shoulder2.x = neck.x ;
+
+            shoulder1.y = neck.y - (totalBranchLength/2.0) ;
+            shoulder2.y = neck.y + (totalBranchLength/2.0) ;
+            break;
+        }
+        case 2:
+        {
+            neck.x = GetX();
+            neck.y = root.y + m_branchNeckLength;
+
+            shoulder1.x = root.x - (totalBranchLength/2.0) ;
+            shoulder2.x = root.x + (totalBranchLength/2.0) ;
+
+            shoulder1.y = neck.y;
+            shoulder2.y = neck.y;
+            break;
+        }
+        case 3:
+        {
+            neck.x = root.x - m_branchNeckLength;
+            neck.y = root.y ;
+
+            shoulder1.x = neck.x ;
+            shoulder2.x = neck.x ;
+
+            shoulder1.y = neck.y - (totalBranchLength/2.0) ;
+            shoulder2.y = neck.y + (totalBranchLength/2.0) ;
+            break;
+        }
+        default:
+        {
+            wxFAIL_MSG( "Unrecognised attachment point in GetBranchingAttachmentInfo." );
+            break;
+        }
+    }
+    return TRUE;
+}
+
+// n is the number of the adjoining line, from 0 to N-1 where N is the number of lines
+// at this attachment point.
+// Get the attachment point where the arc joins the stem, and also the point where the
+// the stem meets the shoulder.
+bool wxShape::GetBranchingAttachmentPoint(int attachment, int n, wxRealPoint& pt, wxRealPoint& stemPt)
+{
+    int physicalAttachment = LogicalToPhysicalAttachment(attachment);
+
+    wxRealPoint root, neck, shoulder1, shoulder2;
+    GetBranchingAttachmentInfo(attachment, root, neck, shoulder1, shoulder2);
+
+    // Assume that we have attachment points 0 to 3: top, right, bottom, left.
+    switch (physicalAttachment)
+    {
+        case 0:
+        {
+            pt.y = neck.y - m_branchStemLength;
+            pt.x = shoulder1.x + n*m_branchSpacing;
+
+            stemPt.x = pt.x;
+            stemPt.y = neck.y;
+            break;
+        }
+        case 2:
+        {
+            pt.y = neck.y + m_branchStemLength;
+            pt.x = shoulder1.x + n*m_branchSpacing;
+
+            stemPt.x = pt.x;
+            stemPt.y = neck.y;
+            break;
+        }
+        case 1:
+        {
+            pt.x = neck.x + m_branchStemLength;
+            pt.y = shoulder1.y + n*m_branchSpacing;
+
+            stemPt.x = neck.x;
+            stemPt.y = pt.y;
+            break;
+        }
+        case 3:
+        {
+            pt.x = neck.x - m_branchStemLength;
+            pt.y = shoulder1.y + n*m_branchSpacing;
+
+            stemPt.x = neck.x;
+            stemPt.y = pt.y;
+            break;
+        }
+        default:
+        {
+            wxFAIL_MSG( "Unrecognised attachment point in GetBranchingAttachmentPoint." );
+            break;
+        }
+    }
+
+    return TRUE;
+}
+
+// Get the number of lines at this attachment position.
+int wxShape::GetAttachmentLineCount(int attachment) const
+{
+    int count = 0;
+    wxNode* node = m_lines.First();
+    while (node)
+    {
+        wxLineShape* lineShape = (wxLineShape*) node->Data();
+        if ((lineShape->GetFrom() == this) && (lineShape->GetAttachmentFrom() == attachment))
+            count ++;
+        else if ((lineShape->GetTo() == this) && (lineShape->GetAttachmentTo() == attachment))
+            count ++;
+
+        node = node->Next();
+    }
+    return count;
+}
+
+// This function gets the root point at the given attachment.
+wxRealPoint wxShape::GetBranchingAttachmentRoot(int attachment)
+{
+    int physicalAttachment = LogicalToPhysicalAttachment(attachment);
+
+    wxRealPoint root;
+
+    double width, height;
+    GetBoundingBoxMax(& width, & height);
+
+    // Assume that we have attachment points 0 to 3: top, right, bottom, left.
+    switch (physicalAttachment)
+    {
+        case 0:
+        {
+            root.x = GetX() ;
+            root.y = GetY() - height/2.0;
+            break;
+        }
+        case 1:
+        {
+            root.x = GetX() + width/2.0;
+            root.y = GetY() ;
+            break;
+        }
+        case 2:
+        {
+            root.x = GetX() ;
+            root.y = GetY() + height/2.0;
+            break;
+        }
+        case 3:
+        {
+            root.x = GetX() - width/2.0;
+            root.y = GetY() ;
+            break;
+        }
+        default:
+        {
+            wxFAIL_MSG( "Unrecognised attachment point in GetBranchingAttachmentRoot." );
+            break;
+        }
+    }
+    return root;
+}
+
+// Draw or erase the branches (not the actual arcs though)
+void wxShape::OnDrawBranches(wxDC& dc, int attachment, bool erase)
+{
+    int count = GetAttachmentLineCount(attachment);
+    if (count == 0)
+        return;
+
+    wxRealPoint root, neck, shoulder1, shoulder2;
+    GetBranchingAttachmentInfo(attachment, root, neck, shoulder1, shoulder2);
+
+    if (erase)
+    {
+        dc.SetPen(*wxWHITE_PEN);
+        dc.SetBrush(*wxWHITE_BRUSH);
+    }
+    else
+    {
+        dc.SetPen(*wxBLACK_PEN);
+        dc.SetBrush(*wxBLACK_BRUSH);
+    }
+
+    // Draw neck
+    dc.DrawLine((long) root.x, (long) root.y, (long) neck.x, (long) neck.y);
+
+    if (count > 1)
+    {
+        // Draw shoulder-to-shoulder line
+        dc.DrawLine((long) shoulder1.x, (long) shoulder1.y, (long) shoulder2.x, (long) shoulder2.y);
+    }
+    // Draw all the little branches
+    int i;
+    for (i = 0; i < count; i++)
+    {
+        wxRealPoint pt, stemPt;
+        GetBranchingAttachmentPoint(attachment, i, pt, stemPt);
+        dc.DrawLine((long) stemPt.x, (long) stemPt.y, (long) pt.x, (long) pt.y);
+
+        if ((GetBranchStyle() & BRANCHING_ATTACHMENT_BLOB) && (count > 1))
+        {
+            long blobSize=6;
+//            dc.DrawEllipse((long) (stemPt.x + 0.5 - (blobSize/2.0)), (long) (stemPt.y + 0.5 - (blobSize/2.0)), blobSize, blobSize);
+            dc.DrawEllipse((long) (stemPt.x - (blobSize/2.0)), (long) (stemPt.y - (blobSize/2.0)), blobSize, blobSize);
+        }
+    }
+}
+
+// Draw or erase the branches (not the actual arcs though)
+void wxShape::OnDrawBranches(wxDC& dc, bool erase)
+{
+    if (m_attachmentMode != ATTACHMENT_MODE_BRANCHING)
+        return;
+
+    int count = GetNumberOfAttachments();
+    int i;
+    for (i = 0; i < count; i++)
+        OnDrawBranches(dc, i, erase);
+}
+
+// Only get the attachment position at the _edge_ of the shape, ignoring
+// branching mode. This is used e.g. to indicate the edge of interest, not the point
+// on the attachment branch.
+bool wxShape::GetAttachmentPositionEdge(int attachment, double *x, double *y,
+                                     int nth, int no_arcs, wxLineShape *line)
+{
+    int oldMode = m_attachmentMode;
+
+    // Calculate as if to edge, not branch
+    if (m_attachmentMode == ATTACHMENT_MODE_BRANCHING)
+        m_attachmentMode = ATTACHMENT_MODE_EDGE;
+    bool success = GetAttachmentPosition(attachment, x, y, nth, no_arcs, line);
+    m_attachmentMode = oldMode;
+
+    return success;
+}
+
+// Rotate the standard attachment point from physical (0 is always North)
+// to logical (0 -> 1 if rotated by 90 degrees)
+int wxShape::PhysicalToLogicalAttachment(int physicalAttachment) const
+{
+    const double pi = 3.1415926535897932384626433832795 ;
+    int i;
+    if (oglRoughlyEqual(GetRotation(), 0.0))
+    {
+        i = physicalAttachment;
+    }
+    else if (oglRoughlyEqual(GetRotation(), (pi/2.0)))
+    {
+        i = physicalAttachment - 1;
+    }
+    else if (oglRoughlyEqual(GetRotation(), pi))
+    {
+        i = physicalAttachment - 2;
+    }
+    else if (oglRoughlyEqual(GetRotation(), (3.0*pi/2.0)))
+    {
+        i = physicalAttachment - 3;
+    }
+    else
+        // Can't handle -- assume the same.
+        return physicalAttachment;
+
+    if (i < 0)
+      i += 4;
+
+    return i;
+}
+
+// Rotate the standard attachment point from logical
+// to physical (0 is always North)
+int wxShape::LogicalToPhysicalAttachment(int logicalAttachment) const
+{
+    const double pi = 3.1415926535897932384626433832795 ;
+    int i;
+    if (oglRoughlyEqual(GetRotation(), 0.0))
+    {
+        i = logicalAttachment;
+    }
+    else if (oglRoughlyEqual(GetRotation(), (pi/2.0)))
+    {
+        i = logicalAttachment + 1;
+    }
+    else if (oglRoughlyEqual(GetRotation(), pi))
+    {
+        i = logicalAttachment + 2;
+    }
+    else if (oglRoughlyEqual(GetRotation(), (3.0*pi/2.0)))
+    {
+        i = logicalAttachment + 3;
+    }
+    else
+        // Can't handle -- assume the same.
+        return logicalAttachment;
+
+    if (i > 3)
+      i -= 4;
+
+    return i;
+}
+
+void wxShape::Rotate(double WXUNUSED(x), double WXUNUSED(y), double theta)
+{
+    const double pi = 3.1415926535897932384626433832795 ;
+    m_rotation = theta;
+    if (m_rotation < 0.0)
+    {
+        m_rotation += 2*pi;
+    }
+    else if (m_rotation > 2*pi)
+    {
+        m_rotation -= 2*pi;
+    }
+}
+