]> git.saurik.com Git - wxWidgets.git/blobdiff - utils/ogl/src/basic.cpp
if the wxTextCtrl is empty set by SetInsertionPointEnd to 0 and not to -1.
[wxWidgets.git] / utils / ogl / src / basic.cpp
index 12867bd404be03aea0f80a4a2607327a68409a43..d93aa76a0c2bb01b396dc86a63de88bcdb821069 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>
@@ -60,7 +58,7 @@
 IMPLEMENT_DYNAMIC_CLASS(wxShapeTextLine, wxObject)
 IMPLEMENT_DYNAMIC_CLASS(wxAttachmentPoint, wxObject)
 
-wxShapeTextLine::wxShapeTextLine(float the_x, float the_y, const wxString& the_line)
+wxShapeTextLine::wxShapeTextLine(double the_x, double the_y, const wxString& the_line)
 {
   m_x = the_x; m_y = the_y; m_line = the_line;
 }
@@ -81,6 +79,22 @@ wxShapeEvtHandler::~wxShapeEvtHandler()
 {
 }
 
+// Creates a copy of this event handler.
+wxShapeEvtHandler* wxShapeEvtHandler::CreateNewCopy()
+{
+  wxShapeEvtHandler* newObject = (wxShapeEvtHandler*) GetClassInfo()->CreateObject();
+
+  wxASSERT( (newObject != NULL) );
+  wxASSERT( (newObject->IsKindOf(CLASSINFO(wxShapeEvtHandler))) );
+
+  newObject->m_previousHandler = newObject;
+
+  CopyData(*newObject);
+
+  return newObject;
+}
+
+
 void wxShapeEvtHandler::OnDelete()
 {
   if (this != GetShape())
@@ -111,13 +125,19 @@ void wxShapeEvtHandler::OnDrawContents(wxDC& dc)
     m_previousHandler->OnDrawContents(dc);
 }
 
-void wxShapeEvtHandler::OnSize(float x, float y)
+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)
     m_previousHandler->OnSize(x, y);
 }
 
-bool wxShapeEvtHandler::OnMovePre(wxDC& dc, float x, float y, float old_x, float old_y, bool display)
+bool wxShapeEvtHandler::OnMovePre(wxDC& dc, double x, double y, double old_x, double old_y, bool display)
 {
   if (m_previousHandler)
     return m_previousHandler->OnMovePre(dc, x, y, old_x, old_y, display);
@@ -125,7 +145,7 @@ bool wxShapeEvtHandler::OnMovePre(wxDC& dc, float x, float y, float old_x, float
     return TRUE;
 }
 
-void wxShapeEvtHandler::OnMovePost(wxDC& dc, float x, float y, float old_x, float old_y, bool display)
+void wxShapeEvtHandler::OnMovePost(wxDC& dc, double x, double y, double old_x, double old_y, bool display)
 {
   if (m_previousHandler)
     m_previousHandler->OnMovePost(dc, x, y, old_x, old_y, display);
@@ -149,55 +169,81 @@ void wxShapeEvtHandler::OnHighlight(wxDC& dc)
     m_previousHandler->OnHighlight(dc);
 }
 
-void wxShapeEvtHandler::OnLeftClick(float x, float y, int keys, int attachment)
+void wxShapeEvtHandler::OnLeftClick(double x, double y, int keys, int attachment)
 {
   if (m_previousHandler)
     m_previousHandler->OnLeftClick(x, y, keys, attachment);
 }
 
-void wxShapeEvtHandler::OnRightClick(float x, float y, int keys, int 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)
     m_previousHandler->OnRightClick(x, y, keys, attachment);
 }
 
-void wxShapeEvtHandler::OnDragLeft(bool draw, float x, float y, int keys, int attachment)
+void wxShapeEvtHandler::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
 {
   if (m_previousHandler)
     m_previousHandler->OnDragLeft(draw, x, y, keys, attachment);
 }
 
-void wxShapeEvtHandler::OnBeginDragLeft(float x, float y, int keys, int attachment)
+void wxShapeEvtHandler::OnBeginDragLeft(double x, double y, int keys, int attachment)
 {
   if (m_previousHandler)
     m_previousHandler->OnBeginDragLeft(x, y, keys, attachment);
 }
 
-void wxShapeEvtHandler::OnEndDragLeft(float x, float y, int keys, int attachment)
+void wxShapeEvtHandler::OnEndDragLeft(double x, double y, int keys, int attachment)
 {
   if (m_previousHandler)
     m_previousHandler->OnEndDragLeft(x, y, keys, attachment);
 }
 
-void wxShapeEvtHandler::OnDragRight(bool draw, float x, float y, int keys, int attachment)
+void wxShapeEvtHandler::OnDragRight(bool draw, double x, double y, int keys, int attachment)
 {
   if (m_previousHandler)
     m_previousHandler->OnDragRight(draw, x, y, keys, attachment);
 }
 
-void wxShapeEvtHandler::OnBeginDragRight(float x, float y, int keys, int attachment)
+void wxShapeEvtHandler::OnBeginDragRight(double x, double y, int keys, int attachment)
 {
   if (m_previousHandler)
     m_previousHandler->OnBeginDragRight(x, y, keys, attachment);
 }
 
-void wxShapeEvtHandler::OnEndDragRight(float x, float y, int keys, int attachment)
+void wxShapeEvtHandler::OnEndDragRight(double x, double y, int keys, int attachment)
 {
   if (m_previousHandler)
     m_previousHandler->OnEndDragRight(x, y, keys, attachment);
 }
 
-void wxShapeEvtHandler::OnDrawOutline(wxDC& dc, float x, float y, float w, float h)
+// Control points ('handles') redirect control to the actual shape, to make it easier
+// to override sizing behaviour.
+void wxShapeEvtHandler::OnSizingDragLeft(wxControlPoint* pt, bool draw, double x, double y, int keys, int attachment)
+{
+  if (m_previousHandler)
+    m_previousHandler->OnSizingDragLeft(pt, draw, x, y, keys, attachment);
+}
+
+void wxShapeEvtHandler::OnSizingBeginDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment)
+{
+  if (m_previousHandler)
+    m_previousHandler->OnSizingBeginDragLeft(pt, x, y, keys, attachment);
+}
+
+void wxShapeEvtHandler::OnSizingEndDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment)
+{
+  if (m_previousHandler)
+    m_previousHandler->OnSizingEndDragLeft(pt, x, y, keys, attachment);
+}
+
+void wxShapeEvtHandler::OnDrawOutline(wxDC& dc, double x, double y, double w, double h)
 {
   if (m_previousHandler)
     m_previousHandler->OnDrawOutline(dc, x, y, w, h);
@@ -215,17 +261,24 @@ void wxShapeEvtHandler::OnEraseControlPoints(wxDC& dc)
     m_previousHandler->OnEraseControlPoints(dc);
 }
 
+// Can override this to prevent or intercept line reordering.
+void wxShapeEvtHandler::OnChangeAttachment(int attachment, wxLineShape* line, wxList& ordering)
+{
+  if (m_previousHandler)
+    m_previousHandler->OnChangeAttachment(attachment, line, ordering);
+}
+
 IMPLEMENT_ABSTRACT_CLASS(wxShape, wxShapeEvtHandler)
 
 wxShape::wxShape(wxShapeCanvas *can)
 {
   m_eventHandler = this;
-  SetHandlerShape(this);
+  SetShape(this);
   m_id = 0;
   m_formatted = FALSE;
   m_canvas = can;
   m_xpos = 0.0; m_ypos = 0.0;
-  m_pen = black_pen;
+  m_pen = g_oglBlackPen;
   m_brush = wxWHITE_BRUSH;
   m_font = g_oglNormalFont;
   m_textColour = wxBLACK;
@@ -233,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;
@@ -251,8 +304,13 @@ wxShape::wxShape(wxShapeCanvas *can)
   m_textMarginY = 5.0;
   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)
@@ -473,45 +531,47 @@ void wxShape::SetDefaultRegionSize()
   wxNode *node = m_regions.First();
   if (!node) return;
   wxShapeRegion *region = (wxShapeRegion *)node->Data();
-  float w, h;
+  double w, h;
   GetBoundingBoxMin(&w, &h);
   region->SetSize(w, h);
 }
 
-bool wxShape::HitTest(float x, float y, int *attachment, float *distance)
+bool wxShape::HitTest(double x, double y, int *attachment, double *distance)
 {
 //  if (!sensitive)
 //    return FALSE;
 
-  float width = 0.0, height = 0.0;
+  double width = 0.0, height = 0.0;
   GetBoundingBoxMin(&width, &height);
   if (fabs(width) < 4.0) width = 4.0;
   if (fabs(height) < 4.0) height = 4.0;
 
-  width += (float)4.0; height += (float)4.0; // Allowance for inaccurate mousing
+  width += (double)4.0; height += (double)4.0; // Allowance for inaccurate mousing
 
-  float left = (float)(m_xpos - (width/2.0));
-  float top = (float)(m_ypos - (height/2.0));
-  float right = (float)(m_xpos + (width/2.0));
-  float bottom = (float)(m_ypos + (height/2.0));
+  double left = (double)(m_xpos - (width/2.0));
+  double top = (double)(m_ypos - (height/2.0));
+  double right = (double)(m_xpos + (width/2.0));
+  double bottom = (double)(m_ypos + (height/2.0));
 
   int nearest_attachment = 0;
 
-
   // If within the bounding box, check the attachment points
   // within the object.
 
   if (x >= left && x <= right && y >= top && y <= bottom)
   {
     int n = GetNumberOfAttachments();
-    float nearest = 999999.0;
+    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++)
     {
-      float xp, yp;
-      if (GetAttachmentPosition(i, &xp, &yp))
+      double xp, yp;
+      if (GetAttachmentPositionEdge(i, &xp, &yp))
       {
-        float l = (float)sqrt(((xp - x) * (xp - x)) +
+        double l = (double)sqrt(((xp - x) * (xp - x)) +
                    ((yp - y) * (yp - y)));
 
         if (l < nearest)
@@ -534,7 +594,7 @@ bool wxShape::HitTest(float x, float y, int *attachment, float *distance)
 static bool GraphicsInSizeToContents = FALSE; // Infinite recursion elimination
 void wxShape::FormatText(wxDC& dc, const wxString& s, int i)
 {
-  float w, h;
+  double w, h;
   ClearText(i);
 
   if (m_regions.Number() < 1)
@@ -549,26 +609,25 @@ void wxShape::FormatText(wxDC& dc, const wxString& s, int i)
 
   region->GetSize(&w, &h);
 
-  wxList *string_list = ::FormatText(dc, s, (w-5), (h-5), region->GetFormatMode());
-  node = string_list->First();
+  wxStringList *stringList = oglFormatText(dc, s, (w-5), (h-5), region->GetFormatMode());
+  node = stringList->First();
   while (node)
   {
     char *s = (char *)node->Data();
     wxShapeTextLine *line = new wxShapeTextLine(0.0, 0.0, s);
     region->GetFormattedText().Append((wxObject *)line);
-    delete node;
-    node = string_list->First();
+    node = node->Next();
   }
-  delete string_list;
-  float actualW = w;
-  float actualH = h;
+  delete stringList;
+  double actualW = w;
+  double actualH = h;
   // Don't try to resize an object with more than one image (this case should be dealt
   // with by overriden handlers)
   if ((region->GetFormatMode() & FORMAT_SIZE_TO_CONTENTS) &&
       (region->GetFormattedText().Number() > 0) &&
       (m_regions.Number() == 1) && !GraphicsInSizeToContents)
   {
-    GetCentredTextExtent(dc, &(region->GetFormattedText()), m_xpos, m_ypos, w, h, &actualW, &actualH);
+    oglGetCentredTextExtent(dc, &(region->GetFormattedText()), m_xpos, m_ypos, w, h, &actualW, &actualH);
     if ((actualW+m_textMarginX != w ) || (actualH+m_textMarginY != h))
     {
       // If we are a descendant of a composite, must make sure the composite gets
@@ -607,13 +666,13 @@ void wxShape::FormatText(wxDC& dc, const wxString& s, int i)
       EraseContents(dc);
     }
   }
-  CentreText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, actualW, actualH, region->GetFormatMode());
+  oglCentreText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, actualW, actualH, region->GetFormatMode());
   m_formatted = TRUE;
 }
 
 void wxShape::Recentre(wxDC& dc)
 {
-  float w, h;
+  double w, h;
   GetBoundingBoxMin(&w, &h);
 
   int noRegions = m_regions.Number();
@@ -623,14 +682,14 @@ void wxShape::Recentre(wxDC& dc)
     if (node)
     {
       wxShapeRegion *region = (wxShapeRegion *)node->Data();
-      CentreText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, w, h, region->GetFormatMode());
+      oglCentreText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, w, h, region->GetFormatMode());
     }
   }
 }
 
-bool wxShape::GetPerimeterPoint(float x1, float y1,
-                                     float x2, float y2,
-                                     float *x3, float *y3)
+bool wxShape::GetPerimeterPoint(double x1, double y1,
+                                     double x2, double y2,
+                                     double *x3, double *y3)
 {
   return FALSE;
 }
@@ -824,8 +883,8 @@ void wxShape::FindRegionNames(wxStringList& list)
 
 void wxShape::AssignNewIds()
 {
-  if (m_id == 0)
-    m_id = NewId();
+//  if (m_id == 0)
+  m_id = NewId();
   wxNode *node = m_children.First();
   while (node)
   {
@@ -856,7 +915,7 @@ void wxShape::OnMoveLinks(wxDC& dc)
 
 void wxShape::OnDrawContents(wxDC& dc)
 {
-  float bound_x, bound_y;
+  double bound_x, bound_y;
   GetBoundingBoxMin(&bound_x, &bound_y);
     if (m_regions.Number() < 1) return;
 
@@ -869,12 +928,12 @@ void wxShape::OnDrawContents(wxDC& dc)
     dc.SetBackgroundMode(wxTRANSPARENT);
     if (!m_formatted)
     {
-      CentreText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, bound_x, bound_y, region->GetFormatMode());
+      oglCentreText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, bound_x, bound_y, region->GetFormatMode());
       m_formatted = TRUE;
     }
     if (!GetDisableLabel())
     {
-      DrawFormattedText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, bound_x, bound_y, region->GetFormatMode());
+      oglDrawFormattedText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, bound_x, bound_y, region->GetFormatMode());
     }
 }
 
@@ -883,16 +942,16 @@ void wxShape::DrawContents(wxDC& dc)
   GetEventHandler()->OnDrawContents(dc);
 }
 
-void wxShape::OnSize(float x, float y)
+void wxShape::OnSize(double x, double y)
 {
 }
 
-bool wxShape::OnMovePre(wxDC& dc, float x, float y, float old_x, float old_y, bool display)
+bool wxShape::OnMovePre(wxDC& dc, double x, double y, double old_x, double old_y, bool display)
 {
   return TRUE;
 }
 
-void wxShape::OnMovePost(wxDC& dc, float x, float y, float old_x, float old_y, bool display)
+void wxShape::OnMovePost(wxDC& dc, double x, double y, double old_x, double old_y, bool display)
 {
 }
 
@@ -917,22 +976,22 @@ void wxShape::OnEraseContents(wxDC& dc)
   if (!m_visible)
     return;
 
-  float maxX, maxY, minX, minY;
-  float xp = GetX();
-  float yp = GetY();
+  double maxX, maxY, minX, minY;
+  double xp = GetX();
+  double yp = GetY();
   GetBoundingBoxMin(&minX, &minY);
   GetBoundingBoxMax(&maxX, &maxY);
-  float topLeftX = (float)(xp - (maxX / 2.0) - 2.0);
-  float topLeftY = (float)(yp - (maxY / 2.0) - 2.0);
+  double topLeftX = (double)(xp - (maxX / 2.0) - 2.0);
+  double topLeftY = (double)(yp - (maxY / 2.0) - 2.0);
 
     int penWidth = 0;
     if (m_pen)
       penWidth = m_pen->GetWidth();
 
-    dc.SetPen(white_background_pen);
-    dc.SetBrush(white_background_brush);
-    dc.DrawRectangle((float)(topLeftX - penWidth), (float)(topLeftY - penWidth),
-                      (float)(maxX + penWidth*2.0 + 4.0), (float)(maxY + penWidth*2.0 + 4.0));
+    dc.SetPen(g_oglWhiteBackgroundPen);
+    dc.SetBrush(g_oglWhiteBackgroundBrush);
+    dc.DrawRectangle(WXROUND(topLeftX - penWidth), WXROUND(topLeftY - penWidth),
+                      WXROUND(maxX + penWidth*2.0 + 4.0), WXROUND(maxY + penWidth*2.0 + 4.0));
 }
 
 void wxShape::EraseLinks(wxDC& dc, int attachment, bool recurse)
@@ -988,89 +1047,173 @@ void wxShape::DrawLinks(wxDC& dc, int attachment, bool recurse)
   }
 }
 
-void wxShape::MoveLineToNewAttachment(wxDC& dc, wxLineShape *to_move,
-                                       float x, float y)
+// Returns TRUE if pt1 <= pt2 in the sense that one point comes before another on an
+// edge of the shape.
+// attachmentPoint is the attachment point (= side) in question.
+
+// This is the default, rectangular implementation.
+bool wxShape::AttachmentSortTest(int attachmentPoint, const wxRealPoint& pt1, const wxRealPoint& pt2)
+{
+    int physicalAttachment = LogicalToPhysicalAttachment(attachmentPoint);
+    switch (physicalAttachment)
+    {
+        case 0:
+        case 2:
+        {
+          return (pt1.x <= pt2.x) ;
+          break;
+        }
+        case 1:
+        case 3:
+        {
+          return (pt1.y <= pt2.y) ;
+          break;
+        }
+    }
+
+    return FALSE;
+}
+
+bool wxShape::MoveLineToNewAttachment(wxDC& dc, wxLineShape *to_move,
+                                       double x, double y)
 {
-  int new_point;
-  float distance;
+  if (GetAttachmentMode() == ATTACHMENT_MODE_NONE)
+      return FALSE;
+
+  int newAttachment, oldAttachment;
+  double distance;
 
   // Is (x, y) on this object? If so, find the new attachment point
   // the user has moved the point to
-  bool hit = HitTest(x, y, &new_point, &distance);
+  bool hit = HitTest(x, y, &newAttachment, &distance);
   if (!hit)
-    return;
+    return FALSE;
 
   EraseLinks(dc);
 
-  int old_attachment;
   if (to_move->GetTo() == this)
-    old_attachment = to_move->GetAttachmentTo();
+    oldAttachment = to_move->GetAttachmentTo();
   else
-    old_attachment = to_move->GetAttachmentFrom();
+    oldAttachment = to_move->GetAttachmentFrom();
+
+  // The links in a new ordering.
+  wxList newOrdering;
+
+  // First, add all links to the new list.
+  wxNode *node = m_lines.First();
+  while (node)
+  {
+    newOrdering.Append(node->Data());
+    node = node->Next();
+  }
 
   // Delete the line object from the list of links; we're going to move
   // it to another position in the list
-  m_lines.DeleteObject(to_move);
+  newOrdering.DeleteObject(to_move);
 
-  float old_x = (float) -9999.9;
-  float old_y = (float) -9999.9;
+  double old_x = (double) -99999.9;
+  double old_y = (double) -99999.9;
 
-  wxNode *node = m_lines.First();
+  node = newOrdering.First();
   bool found = FALSE;
 
-  while (node && !found)
+  while (!found && node)
   {
     wxLineShape *line = (wxLineShape *)node->Data();
-    if ((line->GetTo() == this && old_attachment == line->GetAttachmentTo()) ||
-        (line->GetFrom() == this && old_attachment == line->GetAttachmentFrom()))
+    if ((line->GetTo() == this && oldAttachment == line->GetAttachmentTo()) ||
+        (line->GetFrom() == this && oldAttachment == line->GetAttachmentFrom()))
     {
-      float startX, startY, endX, endY;
-      float xp, yp;
+      double startX, startY, endX, endY;
+      double xp, yp;
       line->GetEnds(&startX, &startY, &endX, &endY);
       if (line->GetTo() == this)
       {
-//        xp = line->m_xpos2 + line->m_xpos;
-//        yp = line->m_ypos2 + line->m_ypos;
-        xp = startX;
-        yp = startY;
-      } else
-      {
-//        xp = line->m_xpos1 + line->m_xpos;
-//        yp = line->m_ypos1 + line->m_ypos;
         xp = endX;
         yp = endY;
+      } else
+      {
+        xp = startX;
+        yp = startY;
       }
 
-      switch (old_attachment)
+      wxRealPoint thisPoint(xp, yp);
+      wxRealPoint lastPoint(old_x, old_y);
+      wxRealPoint newPoint(x, y);
+
+      if (AttachmentSortTest(newAttachment, newPoint, thisPoint) && AttachmentSortTest(newAttachment, lastPoint, newPoint))
       {
-        case 0:
-        case 2:
-        {
-          if (x > old_x && x <= xp)
-          {
-            found = TRUE;
-            m_lines.Insert(node, to_move);
-          }
-          break;
-        }
-        case 1:
-        case 3:
-        {
-          if (y > old_y && y <= yp)
-          {
-            found = TRUE;
-            m_lines.Insert(node, to_move);
-          }
-          break;
-        }
+        found = TRUE;
+        newOrdering.Insert(node, to_move);
       }
+
       old_x = xp;
       old_y = yp;
     }
     node = node->Next();
   }
+
   if (!found)
-    m_lines.Append(to_move);
+    newOrdering.Append(to_move);
+
+  GetEventHandler()->OnChangeAttachment(newAttachment, to_move, newOrdering);
+
+  return TRUE;
+}
+
+void wxShape::OnChangeAttachment(int attachment, wxLineShape* line, wxList& ordering)
+{
+    if (line->GetTo() == this)
+        line->SetAttachmentTo(attachment);
+    else
+        line->SetAttachmentFrom(attachment);
+
+    ApplyAttachmentOrdering(ordering);
+
+    wxClientDC dc(GetCanvas());
+    GetCanvas()->PrepareDC(dc);
+
+    MoveLinks(dc);
+
+    if (!GetCanvas()->GetQuickEditMode()) GetCanvas()->Redraw(dc);
+}
+
+// Reorders the lines according to the given list.
+void wxShape::ApplyAttachmentOrdering(wxList& linesToSort)
+{
+  // This is a temporary store of all the lines.
+  wxList linesStore;
+  
+  wxNode *node = m_lines.First();
+  while (node)
+  {
+    wxLineShape *line = (wxLineShape *)node->Data();
+    linesStore.Append(line);
+    node = node->Next();;
+  }
+
+  m_lines.Clear();
+
+  node = linesToSort.First();
+  while (node)
+  {
+    wxLineShape *line = (wxLineShape *)node->Data();
+    if (linesStore.Member(line))
+    {
+      // Done this one
+      linesStore.DeleteObject(line);
+      m_lines.Append(line);
+    }
+    node = node->Next();
+  }
+
+  // Now add any lines that haven't been listed in linesToSort.
+  node = linesStore.First();
+  while (node)
+  {
+    wxLineShape *line = (wxLineShape *)node->Data();
+    m_lines.Append(line);
+    node = node->Next();
+  }
 }
 
 // Reorders the lines coming into the node image at this attachment
@@ -1124,12 +1267,12 @@ void wxShape::OnHighlight(wxDC& dc)
 {
 }
 
-void wxShape::OnLeftClick(float x, float y, int keys, int attachment)
+void wxShape::OnLeftClick(double x, double y, int keys, int attachment)
 {
   if ((m_sensitivity & OP_CLICK_LEFT) != OP_CLICK_LEFT)
   {
     attachment = 0;
-    float dist;
+    double dist;
     if (m_parent)
     {
       m_parent->HitTest(x, y, &attachment, &dist);
@@ -1139,12 +1282,12 @@ void wxShape::OnLeftClick(float x, float y, int keys, int attachment)
   }
 }
 
-void wxShape::OnRightClick(float x, float y, int keys, int attachment)
+void wxShape::OnRightClick(double x, double y, int keys, int attachment)
 {
   if ((m_sensitivity & OP_CLICK_RIGHT) != OP_CLICK_RIGHT)
   {
     attachment = 0;
-    float dist;
+    double dist;
     if (m_parent)
     {
       m_parent->HitTest(x, y, &attachment, &dist);
@@ -1154,15 +1297,15 @@ void wxShape::OnRightClick(float x, float y, int keys, int attachment)
   }
 }
 
-float DragOffsetX = 0.0;
-float DragOffsetY = 0.0;
+double DragOffsetX = 0.0;
+double DragOffsetY = 0.0;
 
-void wxShape::OnDragLeft(bool draw, float x, float y, int keys, int attachment)
+void wxShape::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
 {
   if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT)
   {
     attachment = 0;
-    float dist;
+    double dist;
     if (m_parent)
     {
       m_parent->HitTest(x, y, &attachment, &dist);
@@ -1180,23 +1323,23 @@ void wxShape::OnDragLeft(bool draw, float x, float y, int keys, int attachment)
   dc.SetPen(dottedPen);
   dc.SetBrush(* wxTRANSPARENT_BRUSH);
 
-  float xx, yy;
+  double xx, yy;
   xx = x + DragOffsetX;
   yy = y + DragOffsetY;
 
   m_canvas->Snap(&xx, &yy);
 //  m_xpos = xx; m_ypos = yy;
-  float w, h;
+  double w, h;
   GetBoundingBoxMax(&w, &h);
   GetEventHandler()->OnDrawOutline(dc, xx, yy, w, h);
 }
 
-void wxShape::OnBeginDragLeft(float x, float y, int keys, int attachment)
+void wxShape::OnBeginDragLeft(double x, double y, int keys, int attachment)
 {
   if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT)
   {
     attachment = 0;
-    float dist;
+    double dist;
     if (m_parent)
     {
       m_parent->HitTest(x, y, &attachment, &dist);
@@ -1211,8 +1354,10 @@ void wxShape::OnBeginDragLeft(float x, float y, int keys, int attachment)
   wxClientDC dc(GetCanvas());
   GetCanvas()->PrepareDC(dc);
 
-  Erase(dc);
-  float xx, yy;
+  // New policy: don't erase shape until end of drag.
+//  Erase(dc);
+
+  double xx, yy;
   xx = x + DragOffsetX;
   yy = y + DragOffsetY;
   m_canvas->Snap(&xx, &yy);
@@ -1223,19 +1368,19 @@ void wxShape::OnBeginDragLeft(float x, float y, int keys, int attachment)
   dc.SetPen(dottedPen);
   dc.SetBrush((* wxTRANSPARENT_BRUSH));
 
-  float w, h;
+  double w, h;
   GetBoundingBoxMax(&w, &h);
   GetEventHandler()->OnDrawOutline(dc, xx, yy, w, h);
   m_canvas->CaptureMouse();
 }
 
-void wxShape::OnEndDragLeft(float x, float y, int keys, int attachment)
+void wxShape::OnEndDragLeft(double x, double y, int keys, int attachment)
 {
   m_canvas->ReleaseMouse();
   if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT)
   {
     attachment = 0;
-    float dist;
+    double dist;
     if (m_parent)
     {
       m_parent->HitTest(x, y, &attachment, &dist);
@@ -1249,20 +1394,24 @@ void wxShape::OnEndDragLeft(float x, float y, int keys, int attachment)
 
   dc.SetLogicalFunction(wxCOPY);
 
-  float xx = x + DragOffsetX;
-  float yy = y + DragOffsetY;
+  double xx = x + DragOffsetX;
+  double yy = y + DragOffsetY;
   m_canvas->Snap(&xx, &yy);
 //  canvas->Snap(&m_xpos, &m_ypos);
+
+  // New policy: erase shape at end of drag.
+  Erase(dc);
+
   Move(dc, xx, yy);
   if (m_canvas && !m_canvas->GetQuickEditMode()) m_canvas->Redraw(dc);
 }
 
-void wxShape::OnDragRight(bool draw, float x, float y, int keys, int attachment)
+void wxShape::OnDragRight(bool draw, double x, double y, int keys, int attachment)
 {
   if ((m_sensitivity & OP_DRAG_RIGHT) != OP_DRAG_RIGHT)
   {
     attachment = 0;
-    float dist;
+    double dist;
     if (m_parent)
     {
       m_parent->HitTest(x, y, &attachment, &dist);
@@ -1272,12 +1421,12 @@ void wxShape::OnDragRight(bool draw, float x, float y, int keys, int attachment)
   }
 }
 
-void wxShape::OnBeginDragRight(float x, float y, int keys, int attachment)
+void wxShape::OnBeginDragRight(double x, double y, int keys, int attachment)
 {
   if ((m_sensitivity & OP_DRAG_RIGHT) != OP_DRAG_RIGHT)
   {
     attachment = 0;
-    float dist;
+    double dist;
     if (m_parent)
     {
       m_parent->HitTest(x, y, &attachment, &dist);
@@ -1287,12 +1436,12 @@ void wxShape::OnBeginDragRight(float x, float y, int keys, int attachment)
   }
 }
 
-void wxShape::OnEndDragRight(float x, float y, int keys, int attachment)
+void wxShape::OnEndDragRight(double x, double y, int keys, int attachment)
 {
   if ((m_sensitivity & OP_DRAG_RIGHT) != OP_DRAG_RIGHT)
   {
     attachment = 0;
-    float dist;
+    double dist;
     if (m_parent)
     {
       m_parent->HitTest(x, y, &attachment, &dist);
@@ -1302,23 +1451,23 @@ void wxShape::OnEndDragRight(float x, float y, int keys, int attachment)
   }
 }
 
-void wxShape::OnDrawOutline(wxDC& dc, float x, float y, float w, float h)
+void wxShape::OnDrawOutline(wxDC& dc, double x, double y, double w, double h)
 {
-  float top_left_x = (float)(x - w/2.0);
-  float top_left_y = (float)(y - h/2.0);
-  float top_right_x = (float)(top_left_x + w);
-  float top_right_y = (float)top_left_y;
-  float bottom_left_x = (float)top_left_x;
-  float bottom_left_y = (float)(top_left_y + h);
-  float bottom_right_x = (float)top_right_x;
-  float bottom_right_y = (float)bottom_left_y;
+  double top_left_x = (double)(x - w/2.0);
+  double top_left_y = (double)(y - h/2.0);
+  double top_right_x = (double)(top_left_x + w);
+  double top_right_y = (double)top_left_y;
+  double bottom_left_x = (double)top_left_x;
+  double bottom_left_y = (double)(top_left_y + h);
+  double bottom_right_x = (double)top_right_x;
+  double bottom_right_y = (double)bottom_left_y;
 
   wxPoint points[5];
-  points[0].x = top_left_x; points[0].y = top_left_y;
-  points[1].x = top_right_x; points[1].y = top_right_y;
-  points[2].x = bottom_right_x; points[2].y = bottom_right_y;
-  points[3].x = bottom_left_x; points[3].y = bottom_left_y;
-  points[4].x = top_left_x; points[4].y = top_left_y;
+  points[0].x = WXROUND(top_left_x); points[0].y = WXROUND(top_left_y);
+  points[1].x = WXROUND(top_right_x); points[1].y = WXROUND(top_right_y);
+  points[2].x = WXROUND(bottom_right_x); points[2].y = WXROUND(bottom_right_y);
+  points[3].x = WXROUND(bottom_left_x); points[3].y = WXROUND(bottom_left_y);
+  points[4].x = WXROUND(top_left_x); points[4].y = WXROUND(top_left_y);
 
   dc.DrawLines(5, points);
 }
@@ -1333,20 +1482,20 @@ void wxShape::Detach()
   m_canvas = NULL;
 }
 
-void wxShape::Move(wxDC& dc, float x, float y, bool display)
+void wxShape::Move(wxDC& dc, double x, double y, bool display)
 {
-  float old_x = m_xpos;
-  float old_y = m_ypos;
-
-  m_xpos = x; m_ypos = y;
+  double old_x = m_xpos;
+  double old_y = m_ypos;
 
   if (!GetEventHandler()->OnMovePre(dc, x, y, old_x, old_y, display))
   {
-    m_xpos = old_x;
-    m_ypos = old_y;
+//    m_xpos = old_x;
+//    m_ypos = old_y;
     return;
   }
 
+  m_xpos = x; m_ypos = y;
+
   ResetControlPoints();
 
   if (display)
@@ -1370,6 +1519,7 @@ void wxShape::Draw(wxDC& dc)
     GetEventHandler()->OnDraw(dc);
     GetEventHandler()->OnDrawContents(dc);
     GetEventHandler()->OnDrawControlPoints(dc);
+    GetEventHandler()->OnDrawBranches(dc);
   }
 }
 
@@ -1403,6 +1553,7 @@ void wxShape::Erase(wxDC& dc)
 {
   GetEventHandler()->OnErase(dc);
   GetEventHandler()->OnEraseControlPoints(dc);
+  GetEventHandler()->OnDrawBranches(dc, TRUE);
 }
 
 void wxShape::EraseContents(wxDC& dc)
@@ -1424,17 +1575,17 @@ void wxShape::AddText(const wxString& string)
   m_formatted = FALSE;
 }
 
-void wxShape::SetSize(float x, float y, bool recursive)
+void wxShape::SetSize(double x, double y, bool recursive)
 {
   SetAttachmentSize(x, y);
   SetDefaultRegionSize();
 }
 
-void wxShape::SetAttachmentSize(float w, float h)
+void wxShape::SetAttachmentSize(double w, double h)
 {
-  float scaleX;
-  float scaleY;
-  float width, height;
+  double scaleX;
+  double scaleY;
+  double width, height;
   GetBoundingBoxMin(&width, &height);
   if (width == 0.0)
     scaleX = 1.0;
@@ -1447,25 +1598,88 @@ void wxShape::SetAttachmentSize(float w, float h)
   while (node)
   {
     wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
-    point->m_x = (float)(point->m_x * scaleX);
-    point->m_y = (float)(point->m_y * scaleY);
+    point->m_x = (double)(point->m_x * scaleX);
+    point->m_y = (double)(point->m_y * scaleY);
     node = node->Next();
   }
 }
 
 // Add line FROM this object
 void wxShape::AddLine(wxLineShape *line, wxShape *other,
-                           int attachFrom, int attachTo)
+                            int attachFrom, int attachTo,
+                            // The line ordering
+                            int positionFrom, int positionTo)
 {
-  if (!m_lines.Member(line))
-    m_lines.Append(line);
+    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);
+
+    if (positionFrom == -1)
+        m_lines.Append(line);
+    else
+    {
+        if (positionFrom < m_lines.Number())
+        {
+            wxNode* node = m_lines.Nth(positionFrom);
+            m_lines.Insert(node, line);
+        }
+        else
+            m_lines.Append(line);
+    }
 
-  if (!other->m_lines.Member(line))
-    other->m_lines.Append(line);
+    if (positionTo == -1)
+        other->m_lines.Append(line);
+    else
+    {
+        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);
+    }
+#endif
 
-  line->SetFrom(this);
-  line->SetTo(other);
-  line->SetAttachments(attachFrom, attachTo);
+    line->SetFrom(this);
+    line->SetTo(other);
+    line->SetAttachments(attachFrom, attachTo);
 }
 
 void wxShape::RemoveLine(wxLineShape *line)
@@ -1479,12 +1693,7 @@ void wxShape::RemoveLine(wxLineShape *line)
 }
 
 #ifdef PROLOGIO
-char *wxShape::GetFunctor()
-{
-  return "node_image";
-}
-
-void wxShape::WritePrologAttributes(wxExpr *clause)
+void wxShape::WriteAttributes(wxExpr *clause)
 {
   clause->AddAttributeValueString("type", GetClassInfo()->GetClassName());
   clause->AddAttributeValue("id", m_id);
@@ -1499,7 +1708,13 @@ void wxShape::WritePrologAttributes(wxExpr *clause)
       clause->AddAttributeValue("pen_style", (long)penStyle);
 
     wxString penColour = wxTheColourDatabase->FindName(m_pen->GetColour());
-    if ((penColour != "") && (penColour != "BLACK"))
+    if (penColour == "")
+    {
+      wxString hex(oglColourToHex(m_pen->GetColour()));
+      hex = wxString("#") + hex;
+      clause->AddAttributeValueString("pen_colour", hex);
+    }
+    else if (penColour != "BLACK")
       clause->AddAttributeValueString("pen_colour", penColour);
   }
 
@@ -1507,7 +1722,13 @@ void wxShape::WritePrologAttributes(wxExpr *clause)
   {
     wxString brushColour = wxTheColourDatabase->FindName(m_brush->GetColour());
 
-    if ((brushColour != "") && (brushColour != "WHITE"))
+    if (brushColour == "")
+    {
+      wxString hex(oglColourToHex(m_brush->GetColour()));
+      hex = wxString("#") + hex;
+      clause->AddAttributeValueString("brush_colour", hex);
+    }
+    else if (brushColour != "WHITE")
       clause->AddAttributeValueString("brush_colour", brushColour);
     
     if (m_brush->GetStyle() != wxSOLID)
@@ -1519,7 +1740,7 @@ void wxShape::WritePrologAttributes(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)
     {
@@ -1546,6 +1767,7 @@ void wxShape::WritePrologAttributes(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);
 
@@ -1555,15 +1777,23 @@ void wxShape::WritePrologAttributes(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));
@@ -1594,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));
@@ -1614,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();
     }
@@ -1645,7 +1875,7 @@ void wxShape::WriteRegions(wxExpr *clause)
   }
 }
 
-void wxShape::ReadPrologAttributes(wxExpr *clause)
+void wxShape::ReadAttributes(wxExpr *clause)
 {
   clause->GetAttributeValue("id", m_id);
   RegisterId(m_id);
@@ -1656,42 +1886,42 @@ void wxShape::ReadPrologAttributes(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;
     while (node)
     {
       wxExpr *string_expr = node;
-      float the_x = 0.0;
-      float the_y = 0.0;
+      double the_x = 0.0;
+      double the_y = 0.0;
       wxString the_string("");
 
       // 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;
 
         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 = (float)first->IntegerValue();
+            else the_x = (double)first->IntegerValue();
 
-            if (second->Type() == PrologReal)
+            if (second->Type() == wxExprReal)
               the_y = second->RealValue();
-            else the_y = (float)second->IntegerValue();
+            else the_y = (double)second->IntegerValue();
 
             the_string = third->StringValue();
           }
@@ -1709,7 +1939,7 @@ void wxShape::ReadPrologAttributes(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);
@@ -1725,7 +1955,7 @@ void wxShape::ReadPrologAttributes(wxExpr *clause)
 
   int iVal = (int) m_attachmentMode;
   clause->GetAttributeValue("use_attachments", iVal);
-  m_attachmentMode = (iVal != 0);
+  m_attachmentMode = iVal;
 
   clause->GetAttributeValue("sensitivity", m_sensitivity);
 
@@ -1744,10 +1974,28 @@ void wxShape::ReadPrologAttributes(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);
@@ -1759,17 +2007,31 @@ void wxShape::ReadPrologAttributes(wxExpr *clause)
   if (brush_string == "")
     brush_string = "WHITE";
 
-  m_pen = wxThePenList->FindOrCreatePen(pen_string, pen_width, pen_style);
+  if (pen_string[0] == '#')
+  {
+    wxColour col(oglHexToColour(pen_string.After('#')));
+    m_pen = wxThePenList->FindOrCreatePen(col, pen_width, pen_style);
+  }
+  else
+    m_pen = wxThePenList->FindOrCreatePen(pen_string, pen_width, pen_style);
+
   if (!m_pen)
     m_pen = wxBLACK_PEN;
 
-  m_brush = wxTheBrushList->FindOrCreateBrush(brush_string, brush_style);
+  if (brush_string[0] == '#')
+  {
+    wxColour col(oglHexToColour(brush_string.After('#')));
+    m_brush = wxTheBrushList->FindOrCreateBrush(col, brush_style);
+  }
+  else
+    m_brush = wxTheBrushList->FindOrCreateBrush(brush_string, brush_style);
+
   if (!m_brush)
     m_brush = wxWHITE_BRUSH;
 
   int point_size = 10;
   clause->GetAttributeValue("point_size", point_size);
-  SetFont(MatchFont(point_size));
+  SetFont(oglMatchFont(point_size));
 
   // Read user-defined attachment points, if any
   wxExpr *attachmentList = clause->AttributeValue("user_attachments");
@@ -1823,14 +2085,14 @@ void wxShape::ReadRegions(wxExpr *clause)
 
     wxString regionName("");
     wxString regionText("");
-    float x = 0.0;
-    float y = 0.0;
-    float width = 0.0;
-    float height = 0.0;
-    float minWidth = 5.0;
-    float minHeight = 5.0;
-    float m_regionProportionX = -1.0;
-    float m_regionProportionY = -1.0;
+    double x = 0.0;
+    double y = 0.0;
+    double width = 0.0;
+    double height = 0.0;
+    double minWidth = 5.0;
+    double minHeight = 5.0;
+    double m_regionProportionX = -1.0;
+    double m_regionProportionY = -1.0;
     int formatMode = FORMAT_NONE;
     int fontSize = 10;
     int fontFamily = wxSWISS;
@@ -1840,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);
@@ -1876,7 +2138,7 @@ void wxShape::ReadRegions(wxExpr *clause)
       m_regionProportionX = propXExpr->RealValue();
       m_regionProportionY = propYExpr->RealValue();
 
-      formatMode = (formatExpr->IntegerValue() != 0);
+      formatMode = (int) formatExpr->IntegerValue();
       fontSize = (int)sizeExpr->IntegerValue();
       fontFamily = (int)familyExpr->IntegerValue();
       fontStyle = (int)styleExpr->IntegerValue();
@@ -1918,41 +2180,41 @@ 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)
       {
         wxExpr *string_expr = node;
-        float the_x = 0.0;
-        float the_y = 0.0;
+        double the_x = 0.0;
+        double the_y = 0.0;
         wxString the_string("");
 
         // 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;
 
           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 = (float)first->IntegerValue();
+            else the_x = (double)first->IntegerValue();
 
-            if (second->Type() == PrologReal)
+            if (second->Type() == wxExprReal)
               the_y = second->RealValue();
-            else the_y = (float)second->IntegerValue();
+            else the_y = (double)second->IntegerValue();
 
             the_string = third->StringValue();
           }
@@ -2002,12 +2264,14 @@ void wxShape::ReadRegions(wxExpr *clause)
 
 void wxShape::Copy(wxShape& copy)
 {
+  copy.m_id = m_id;
   copy.m_xpos = m_xpos;
   copy.m_ypos = m_ypos;
   copy.m_pen = m_pen;
   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;
@@ -2028,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();
@@ -2052,35 +2320,77 @@ void wxShape::Copy(wxShape& copy)
     copy.m_attachmentPoints.Append((wxObject *)newPoint);
     node = node->Next();
   }
+
+  // Copy lines
+  copy.m_lines.Clear();
+  node = m_lines.First();
+  while (node)
+  {
+    wxLineShape* line = (wxLineShape*) node->Data();
+    copy.m_lines.Append(line);
+    node = node->Next();
+  }
 }
 
 // Create and return a new, fully copied object.
-wxShape *wxShape::CreateNewCopy(wxShapeCanvas *theCanvas)
+wxShape *wxShape::CreateNewCopy(bool resetMapping, bool recompute)
 {
-  wxObjectCopyMapping.Clear();
-  wxShape *newObject = PrivateCopy();
-  if (theCanvas)
-    newObject->AddToCanvas(theCanvas);
-  newObject->Recompute();
+  if (resetMapping)
+    oglObjectCopyMapping.Clear();
+
+  wxShape* newObject = (wxShape*) GetClassInfo()->CreateObject();
+
+  wxASSERT( (newObject != NULL) );
+  wxASSERT( (newObject->IsKindOf(CLASSINFO(wxShape))) );
+
+  Copy(*newObject);
+
+  if (GetEventHandler() != this)
+  {
+    wxShapeEvtHandler* newHandler = GetEventHandler()->CreateNewCopy();
+    newObject->SetEventHandler(newHandler);
+    newObject->SetPreviousHandler(NULL);
+    newHandler->SetPreviousHandler(newObject);
+    newHandler->SetShape(newObject);
+  }
+
+  if (recompute)
+    newObject->Recompute();
   return newObject;
 }
 
+// Does the copying for this object, including copying event
+// handler data if any. Calls the virtual Copy function.
+void wxShape::CopyWithHandler(wxShape& copy)
+{
+    Copy(copy);
+
+    if (GetEventHandler() != this)
+    {
+        wxASSERT( copy.GetEventHandler() != NULL );
+        wxASSERT( copy.GetEventHandler() != (&copy) );
+        wxASSERT( GetEventHandler()->GetClassInfo() == copy.GetEventHandler()->GetClassInfo() );
+        GetEventHandler()->CopyData(* (copy.GetEventHandler()));
+    }
+}
+
+
 // Default - make 6 control points
 void wxShape::MakeControlPoints()
 {
-  float maxX, maxY, minX, minY;
+  double maxX, maxY, minX, minY;
 
   GetBoundingBoxMax(&maxX, &maxY);
   GetBoundingBoxMin(&minX, &minY);
 
-  float widthMin = (float)(minX + CONTROL_POINT_SIZE + 2);
-  float heightMin = (float)(minY + CONTROL_POINT_SIZE + 2);
+  double widthMin = (double)(minX + CONTROL_POINT_SIZE + 2);
+  double heightMin = (double)(minY + CONTROL_POINT_SIZE + 2);
 
   // Offsets from main object
-  float top = (float)(- (heightMin / 2.0));
-  float bottom = (float)(heightMin / 2.0 + (maxY - minY));
-  float left = (float)(- (widthMin / 2.0));
-  float right = (float)(widthMin / 2.0 + (maxX - minX));
+  double top = (double)(- (heightMin / 2.0));
+  double bottom = (double)(heightMin / 2.0 + (maxY - minY));
+  double left = (double)(- (widthMin / 2.0));
+  double right = (double)(widthMin / 2.0 + (maxX - minX));
 
   wxControlPoint *control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, top, 
                                            CONTROL_POINT_DIAGONAL);
@@ -2153,19 +2463,19 @@ void wxShape::ResetControlPoints()
   if (m_controlPoints.Number() < 1)
     return;
 
-  float maxX, maxY, minX, minY;
+  double maxX, maxY, minX, minY;
 
   GetBoundingBoxMax(&maxX, &maxY);
   GetBoundingBoxMin(&minX, &minY);
 
-  float widthMin = (float)(minX + CONTROL_POINT_SIZE + 2);
-  float heightMin = (float)(minY + CONTROL_POINT_SIZE + 2);
+  double widthMin = (double)(minX + CONTROL_POINT_SIZE + 2);
+  double heightMin = (double)(minY + CONTROL_POINT_SIZE + 2);
 
   // Offsets from main object
-  float top = (float)(- (heightMin / 2.0));
-  float bottom = (float)(heightMin / 2.0 + (maxY - minY));
-  float left = (float)(- (widthMin / 2.0));
-  float right = (float)(widthMin / 2.0 + (maxX - minX));
+  double top = (double)(- (heightMin / 2.0));
+  double bottom = (double)(heightMin / 2.0 + (maxY - minY));
+  double left = (double)(- (widthMin / 2.0));
+  double right = (double)(widthMin / 2.0 + (maxX - minX));
 
   wxNode *node = m_controlPoints.First();
   wxControlPoint *control = (wxControlPoint *)node->Data();
@@ -2323,7 +2633,7 @@ bool wxShape::AncestorSelected() const
     return GetParent()->AncestorSelected();
 }
 
-int wxShape::GetNumberOfAttachments()
+int wxShape::GetNumberOfAttachments() const
 {
   // Should return the MAXIMUM attachment point id here,
   // so higher-level functions can iterate through all attachments,
@@ -2345,10 +2655,12 @@ int wxShape::GetNumberOfAttachments()
   }
 }
 
-bool wxShape::AttachmentIsValid(int attachment)
+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)
@@ -2361,36 +2673,105 @@ bool wxShape::AttachmentIsValid(int attachment)
   return FALSE;
 }
 
-bool wxShape::GetAttachmentPosition(int attachment, float *x, float *y, 
+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 = (float)(m_xpos + point->m_x);
-        *y = (float)(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(float *w, float *h)
+void wxShape::GetBoundingBoxMax(double *w, double *h)
 {
-  float ww, hh;
+  double ww, hh;
   GetBoundingBoxMin(&ww, &hh);
   if (m_shadowMode != SHADOW_NONE)
   {
@@ -2432,3 +2813,462 @@ void wxShape::ClearPointList(wxList& list)
     list.Clear();
 }
 
+// Assuming the attachment lies along a vertical or horizontal line,
+// calculate the position on that point.
+wxRealPoint wxShape::CalcSimpleAttachment(const wxRealPoint& pt1, const wxRealPoint& pt2,
+    int nth, int noArcs, wxLineShape* line)
+{
+    bool isEnd = (line && line->IsEnd(this));
+
+    // Are we horizontal or vertical?
+    bool isHorizontal = (oglRoughlyEqual(pt1.y, pt2.y) == TRUE);
+
+    double x, y;
+
+    if (isHorizontal)
+    {
+        wxRealPoint firstPoint, secondPoint;
+        if (pt1.x > pt2.x)
+        {
+            firstPoint = pt2;
+            secondPoint = pt1;
+        }
+        else
+        {
+            firstPoint = pt1;
+            secondPoint = pt2;
+        }
+
+        if (m_spaceAttachments)
+        {
+          if (line && (line->GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE))
+          {
+            // Align line according to the next handle along
+            wxRealPoint *point = line->GetNextControlPoint(this);
+            if (point->x < firstPoint.x)
+              x = firstPoint.x;
+            else if (point->x > secondPoint.x)
+              x = secondPoint.x;
+            else
+              x = point->x;
+          }
+          else
+            x = firstPoint.x + (nth + 1)*(secondPoint.x - firstPoint.x)/(noArcs + 1);
+        }
+        else x = (secondPoint.x - firstPoint.x)/2.0; // Midpoint
+
+        y = pt1.y;
+    }
+    else
+    {
+        wxASSERT( oglRoughlyEqual(pt1.x, pt2.x) == TRUE );
+
+        wxRealPoint firstPoint, secondPoint;
+        if (pt1.y > pt2.y)
+        {
+            firstPoint = pt2;
+            secondPoint = pt1;
+        }
+        else
+        {
+            firstPoint = pt1;
+            secondPoint = pt2;
+        }
+
+        if (m_spaceAttachments)
+        {
+          if (line && (line->GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE))
+          {
+            // Align line according to the next handle along
+            wxRealPoint *point = line->GetNextControlPoint(this);
+            if (point->y < firstPoint.y)
+              y = firstPoint.y;
+            else if (point->y > secondPoint.y)
+              y = secondPoint.y;
+            else
+              y = point->y;
+          }
+          else
+            y = firstPoint.y + (nth + 1)*(secondPoint.y - firstPoint.y)/(noArcs + 1);
+        }
+        else y = (secondPoint.y - firstPoint.y)/2.0; // Midpoint
+
+        x = pt1.x;
+    }
+
+    return wxRealPoint(x, y);
+}
+
+// Return the zero-based position in m_lines of line.
+int wxShape::GetLinePosition(wxLineShape* line)
+{
+    int i = 0;
+    for (i = 0; i < m_lines.Number(); i++)
+        if ((wxLineShape*) (m_lines.Nth(i)->Data()) == line)
+            return i;
+
+    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;
+    }
+}
+