home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2233.zip / wxOS2-2_3_3.zip / wxWindows-2.3.3 / contrib / src / ogl / basic.cpp next >
C/C++ Source or Header  |  2002-03-20  |  91KB  |  3,302 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        basic.cpp
  3. // Purpose:     Basic OGL classes
  4. // Author:      Julian Smart
  5. // Modified by:
  6. // Created:     12/07/98
  7. // RCS-ID:      $Id: basic.cpp,v 1.8 2002/03/17 00:19:43 RD Exp $
  8. // Copyright:   (c) Julian Smart
  9. // Licence:       wxWindows licence
  10. /////////////////////////////////////////////////////////////////////////////
  11.  
  12. #ifdef __GNUG__
  13. #pragma implementation "basic.h"
  14. #endif
  15.  
  16. // For compilers that support precompilation, includes "wx.h".
  17. #include "wx/wxprec.h"
  18.  
  19. #ifdef __BORLANDC__
  20. #pragma hdrstop
  21. #endif
  22.  
  23. #ifndef WX_PRECOMP
  24. #include <wx/wx.h>
  25. #endif
  26.  
  27. #include <wx/wxexpr.h>
  28.  
  29. #ifdef new
  30. #undef new
  31. #endif
  32.  
  33. #if wxUSE_IOSTREAMH
  34. #include <iostream.h>
  35. #else
  36. #include <iostream>
  37. #endif
  38.  
  39. #include <stdio.h>
  40. #include <ctype.h>
  41. #include <math.h>
  42.  
  43. #include <wx/ogl/basic.h>
  44. #include <wx/ogl/basicp.h>
  45. #include <wx/ogl/composit.h>
  46. #include <wx/ogl/lines.h>
  47. #include <wx/ogl/canvas.h>
  48. #include <wx/ogl/divided.h>
  49. #include <wx/ogl/misc.h>
  50.  
  51. // Control point types
  52. // Rectangle and most other shapes
  53. #define CONTROL_POINT_VERTICAL   1
  54. #define CONTROL_POINT_HORIZONTAL 2
  55. #define CONTROL_POINT_DIAGONAL   3
  56.  
  57. // Line
  58. #define CONTROL_POINT_ENDPOINT_TO 4
  59. #define CONTROL_POINT_ENDPOINT_FROM 5
  60. #define CONTROL_POINT_LINE       6
  61.  
  62. IMPLEMENT_DYNAMIC_CLASS(wxShapeTextLine, wxObject)
  63. IMPLEMENT_DYNAMIC_CLASS(wxAttachmentPoint, wxObject)
  64.  
  65. wxShapeTextLine::wxShapeTextLine(double the_x, double the_y, const wxString& the_line)
  66. {
  67.   m_x = the_x; m_y = the_y; m_line = the_line;
  68. }
  69.  
  70. wxShapeTextLine::~wxShapeTextLine()
  71. {
  72. }
  73.  
  74. IMPLEMENT_ABSTRACT_CLASS(wxShapeEvtHandler, wxObject)
  75.  
  76. wxShapeEvtHandler::wxShapeEvtHandler(wxShapeEvtHandler *prev, wxShape *shape)
  77. {
  78.   m_previousHandler = prev;
  79.   m_handlerShape = shape;
  80. }
  81.  
  82. wxShapeEvtHandler::~wxShapeEvtHandler()
  83. {
  84. }
  85.  
  86. // Creates a copy of this event handler.
  87. wxShapeEvtHandler* wxShapeEvtHandler::CreateNewCopy()
  88. {
  89.   wxShapeEvtHandler* newObject = (wxShapeEvtHandler*) GetClassInfo()->CreateObject();
  90.  
  91.   wxASSERT( (newObject != NULL) );
  92.   wxASSERT( (newObject->IsKindOf(CLASSINFO(wxShapeEvtHandler))) );
  93.  
  94.   newObject->m_previousHandler = newObject;
  95.  
  96.   CopyData(*newObject);
  97.  
  98.   return newObject;
  99. }
  100.  
  101.  
  102. void wxShapeEvtHandler::OnDelete()
  103. {
  104.   if (this != GetShape())
  105.     delete this;
  106. }
  107.  
  108. void wxShapeEvtHandler::OnDraw(wxDC& dc)
  109. {
  110.   if (m_previousHandler)
  111.     m_previousHandler->OnDraw(dc);
  112. }
  113.  
  114. void wxShapeEvtHandler::OnMoveLinks(wxDC& dc)
  115. {
  116.   if (m_previousHandler)
  117.     m_previousHandler->OnMoveLinks(dc);
  118. }
  119.  
  120. void wxShapeEvtHandler::OnMoveLink(wxDC& dc, bool moveControlPoints)
  121. {
  122.   if (m_previousHandler)
  123.     m_previousHandler->OnMoveLink(dc, moveControlPoints);
  124. }
  125.  
  126. void wxShapeEvtHandler::OnDrawContents(wxDC& dc)
  127. {
  128.   if (m_previousHandler)
  129.     m_previousHandler->OnDrawContents(dc);
  130. }
  131.  
  132. void wxShapeEvtHandler::OnDrawBranches(wxDC& dc, bool erase)
  133. {
  134.   if (m_previousHandler)
  135.     m_previousHandler->OnDrawBranches(dc, erase);
  136. }
  137.  
  138. void wxShapeEvtHandler::OnSize(double x, double y)
  139. {
  140.   if (m_previousHandler)
  141.     m_previousHandler->OnSize(x, y);
  142. }
  143.  
  144. bool wxShapeEvtHandler::OnMovePre(wxDC& dc, double x, double y, double old_x, double old_y, bool display)
  145. {
  146.   if (m_previousHandler)
  147.     return m_previousHandler->OnMovePre(dc, x, y, old_x, old_y, display);
  148.   else
  149.     return TRUE;
  150. }
  151.  
  152. void wxShapeEvtHandler::OnMovePost(wxDC& dc, double x, double y, double old_x, double old_y, bool display)
  153. {
  154.   if (m_previousHandler)
  155.     m_previousHandler->OnMovePost(dc, x, y, old_x, old_y, display);
  156. }
  157.  
  158. void wxShapeEvtHandler::OnErase(wxDC& dc)
  159. {
  160.   if (m_previousHandler)
  161.     m_previousHandler->OnErase(dc);
  162. }
  163.  
  164. void wxShapeEvtHandler::OnEraseContents(wxDC& dc)
  165. {
  166.   if (m_previousHandler)
  167.     m_previousHandler->OnEraseContents(dc);
  168. }
  169.  
  170. void wxShapeEvtHandler::OnHighlight(wxDC& dc)
  171. {
  172.   if (m_previousHandler)
  173.     m_previousHandler->OnHighlight(dc);
  174. }
  175.  
  176. void wxShapeEvtHandler::OnLeftClick(double x, double y, int keys, int attachment)
  177. {
  178.   if (m_previousHandler)
  179.     m_previousHandler->OnLeftClick(x, y, keys, attachment);
  180. }
  181.  
  182. void wxShapeEvtHandler::OnLeftDoubleClick(double x, double y, int keys, int attachment)
  183. {
  184.   if (m_previousHandler)
  185.     m_previousHandler->OnLeftDoubleClick(x, y, keys, attachment);
  186. }
  187.  
  188. void wxShapeEvtHandler::OnRightClick(double x, double y, int keys, int attachment)
  189. {
  190.   if (m_previousHandler)
  191.     m_previousHandler->OnRightClick(x, y, keys, attachment);
  192. }
  193.  
  194. void wxShapeEvtHandler::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
  195. {
  196.   if (m_previousHandler)
  197.     m_previousHandler->OnDragLeft(draw, x, y, keys, attachment);
  198. }
  199.  
  200. void wxShapeEvtHandler::OnBeginDragLeft(double x, double y, int keys, int attachment)
  201. {
  202.   if (m_previousHandler)
  203.     m_previousHandler->OnBeginDragLeft(x, y, keys, attachment);
  204. }
  205.  
  206. void wxShapeEvtHandler::OnEndDragLeft(double x, double y, int keys, int attachment)
  207. {
  208.   if (m_previousHandler)
  209.     m_previousHandler->OnEndDragLeft(x, y, keys, attachment);
  210. }
  211.  
  212. void wxShapeEvtHandler::OnDragRight(bool draw, double x, double y, int keys, int attachment)
  213. {
  214.   if (m_previousHandler)
  215.     m_previousHandler->OnDragRight(draw, x, y, keys, attachment);
  216. }
  217.  
  218. void wxShapeEvtHandler::OnBeginDragRight(double x, double y, int keys, int attachment)
  219. {
  220.   if (m_previousHandler)
  221.     m_previousHandler->OnBeginDragRight(x, y, keys, attachment);
  222. }
  223.  
  224. void wxShapeEvtHandler::OnEndDragRight(double x, double y, int keys, int attachment)
  225. {
  226.   if (m_previousHandler)
  227.     m_previousHandler->OnEndDragRight(x, y, keys, attachment);
  228. }
  229.  
  230. // Control points ('handles') redirect control to the actual shape, to make it easier
  231. // to override sizing behaviour.
  232. void wxShapeEvtHandler::OnSizingDragLeft(wxControlPoint* pt, bool draw, double x, double y, int keys, int attachment)
  233. {
  234.   if (m_previousHandler)
  235.     m_previousHandler->OnSizingDragLeft(pt, draw, x, y, keys, attachment);
  236. }
  237.  
  238. void wxShapeEvtHandler::OnSizingBeginDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment)
  239. {
  240.   if (m_previousHandler)
  241.     m_previousHandler->OnSizingBeginDragLeft(pt, x, y, keys, attachment);
  242. }
  243.  
  244. void wxShapeEvtHandler::OnSizingEndDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment)
  245. {
  246.   if (m_previousHandler)
  247.     m_previousHandler->OnSizingEndDragLeft(pt, x, y, keys, attachment);
  248. }
  249.  
  250. void wxShapeEvtHandler::OnDrawOutline(wxDC& dc, double x, double y, double w, double h)
  251. {
  252.   if (m_previousHandler)
  253.     m_previousHandler->OnDrawOutline(dc, x, y, w, h);
  254. }
  255.  
  256. void wxShapeEvtHandler::OnDrawControlPoints(wxDC& dc)
  257. {
  258.   if (m_previousHandler)
  259.     m_previousHandler->OnDrawControlPoints(dc);
  260. }
  261.  
  262. void wxShapeEvtHandler::OnEraseControlPoints(wxDC& dc)
  263. {
  264.   if (m_previousHandler)
  265.     m_previousHandler->OnEraseControlPoints(dc);
  266. }
  267.  
  268. // Can override this to prevent or intercept line reordering.
  269. void wxShapeEvtHandler::OnChangeAttachment(int attachment, wxLineShape* line, wxList& ordering)
  270. {
  271.   if (m_previousHandler)
  272.     m_previousHandler->OnChangeAttachment(attachment, line, ordering);
  273. }
  274.  
  275. IMPLEMENT_ABSTRACT_CLASS(wxShape, wxShapeEvtHandler)
  276.  
  277. wxShape::wxShape(wxShapeCanvas *can)
  278. {
  279.   m_eventHandler = this;
  280.   SetShape(this);
  281.   m_id = 0;
  282.   m_formatted = FALSE;
  283.   m_canvas = can;
  284.   m_xpos = 0.0; m_ypos = 0.0;
  285.   m_pen = g_oglBlackPen;
  286.   m_brush = wxWHITE_BRUSH;
  287.   m_font = g_oglNormalFont;
  288.   m_textColour = wxBLACK;
  289.   m_textColourName = "BLACK";
  290.   m_visible = FALSE;
  291.   m_selected = FALSE;
  292.   m_attachmentMode = ATTACHMENT_MODE_NONE;
  293.   m_spaceAttachments = TRUE;
  294.   m_disableLabel = FALSE;
  295.   m_fixedWidth = FALSE;
  296.   m_fixedHeight = FALSE;
  297.   m_drawHandles = TRUE;
  298.   m_sensitivity = OP_ALL;
  299.   m_draggable = TRUE;
  300.   m_parent = NULL;
  301.   m_formatMode = FORMAT_CENTRE_HORIZ | FORMAT_CENTRE_VERT;
  302.   m_shadowMode = SHADOW_NONE;
  303.   m_shadowOffsetX = 6;
  304.   m_shadowOffsetY = 6;
  305.   m_shadowBrush = wxBLACK_BRUSH;
  306.   m_textMarginX = 5;
  307.   m_textMarginY = 5;
  308.   m_regionName = "0";
  309.   m_centreResize = TRUE;
  310.   m_maintainAspectRatio = FALSE;
  311.   m_highlighted = FALSE;
  312.   m_rotation = 0.0;
  313.   m_branchNeckLength = 10;
  314.   m_branchStemLength = 10;
  315.   m_branchSpacing = 10;
  316.   m_branchStyle = BRANCHING_ATTACHMENT_NORMAL;
  317.  
  318.   // Set up a default region. Much of the above will be put into
  319.   // the region eventually (the duplication is for compatibility)
  320.   wxShapeRegion *region = new wxShapeRegion;
  321.   m_regions.Append(region);
  322.   region->SetName("0");
  323.   region->SetFont(g_oglNormalFont);
  324.   region->SetFormatMode(FORMAT_CENTRE_HORIZ | FORMAT_CENTRE_VERT);
  325.   region->SetColour("BLACK");
  326. }
  327.  
  328. wxShape::~wxShape()
  329. {
  330.   if (m_parent)
  331.     m_parent->GetChildren().DeleteObject(this);
  332.  
  333.   ClearText();
  334.   ClearRegions();
  335.   ClearAttachments();
  336.  
  337.   if (m_canvas)
  338.     m_canvas->RemoveShape(this);
  339.  
  340.   GetEventHandler()->OnDelete();
  341. }
  342.  
  343. void wxShape::SetHighlight(bool hi, bool recurse)
  344. {
  345.   m_highlighted = hi;
  346.   if (recurse)
  347.   {
  348.     wxNode *node = m_children.First();
  349.     while (node)
  350.     {
  351.       wxShape *child = (wxShape *)node->Data();
  352.       child->SetHighlight(hi, recurse);
  353.       node = node->Next();
  354.     }
  355.   }
  356. }
  357.  
  358. void wxShape::SetSensitivityFilter(int sens, bool recursive)
  359. {
  360.   if (sens & OP_DRAG_LEFT)
  361.     m_draggable = TRUE;
  362.   else
  363.     m_draggable = FALSE;
  364.  
  365.   m_sensitivity = sens;
  366.   if (recursive)
  367.   {
  368.     wxNode *node = m_children.First();
  369.     while (node)
  370.     {
  371.       wxShape *obj = (wxShape *)node->Data();
  372.       obj->SetSensitivityFilter(sens, TRUE);
  373.       node = node->Next();
  374.     }
  375.   }
  376. }
  377.  
  378. void wxShape::SetDraggable(bool drag, bool recursive)
  379. {
  380.   m_draggable = drag;
  381.   if (m_draggable)
  382.     m_sensitivity |= OP_DRAG_LEFT;
  383.   else
  384.     if (m_sensitivity & OP_DRAG_LEFT)
  385.       m_sensitivity = m_sensitivity - OP_DRAG_LEFT;
  386.  
  387.   if (recursive)
  388.   {
  389.     wxNode *node = m_children.First();
  390.     while (node)
  391.     {
  392.       wxShape *obj = (wxShape *)node->Data();
  393.       obj->SetDraggable(drag, TRUE);
  394.       node = node->Next();
  395.     }
  396.   }
  397. }
  398.  
  399. void wxShape::SetDrawHandles(bool drawH)
  400. {
  401.   m_drawHandles = drawH;
  402.   wxNode *node = m_children.First();
  403.   while (node)
  404.   {
  405.     wxShape *obj = (wxShape *)node->Data();
  406.     obj->SetDrawHandles(drawH);
  407.     node = node->Next();
  408.   }
  409. }
  410.  
  411. void wxShape::SetShadowMode(int mode, bool redraw)
  412. {
  413.   if (redraw && GetCanvas())
  414.   {
  415.     wxClientDC dc(GetCanvas());
  416.     GetCanvas()->PrepareDC(dc);
  417.     Erase(dc);
  418.  
  419.     m_shadowMode = mode;
  420.  
  421.     Draw(dc);
  422.   }
  423.   else
  424.   {
  425.     m_shadowMode = mode;
  426.   }
  427. }
  428.  
  429. void wxShape::SetCanvas(wxShapeCanvas *theCanvas)
  430. {
  431.   m_canvas = theCanvas;
  432.   wxNode *node = m_children.First();
  433.   while (node)
  434.   {
  435.     wxShape *child = (wxShape *)node->Data();
  436.     child->SetCanvas(theCanvas);
  437.     node = node->Next();
  438.   }
  439. }
  440.  
  441. void wxShape::AddToCanvas(wxShapeCanvas *theCanvas, wxShape *addAfter)
  442. {
  443.   theCanvas->AddShape(this, addAfter);
  444.   wxNode *node = m_children.First();
  445.   wxShape *lastImage = this;
  446.   while (node)
  447.   {
  448.     wxShape *object = (wxShape *)node->Data();
  449.     object->AddToCanvas(theCanvas, lastImage);
  450.     lastImage = object;
  451.  
  452.     node = node->Next();
  453.   }
  454. }
  455.  
  456. // Insert at front of canvas
  457. void wxShape::InsertInCanvas(wxShapeCanvas *theCanvas)
  458. {
  459.   theCanvas->InsertShape(this);
  460.   wxNode *node = m_children.First();
  461.   wxShape *lastImage = this;
  462.   while (node)
  463.   {
  464.     wxShape *object = (wxShape *)node->Data();
  465.     object->AddToCanvas(theCanvas, lastImage);
  466.     lastImage = object;
  467.  
  468.     node = node->Next();
  469.   }
  470. }
  471.  
  472. void wxShape::RemoveFromCanvas(wxShapeCanvas *theCanvas)
  473. {
  474.   if (Selected())
  475.     Select(FALSE);
  476.   theCanvas->RemoveShape(this);
  477.   wxNode *node = m_children.First();
  478.   while (node)
  479.   {
  480.     wxShape *object = (wxShape *)node->Data();
  481.     object->RemoveFromCanvas(theCanvas);
  482.  
  483.     node = node->Next();
  484.   }
  485. }
  486.  
  487. void wxShape::ClearAttachments()
  488. {
  489.   wxNode *node = m_attachmentPoints.First();
  490.   while (node)
  491.   {
  492.     wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
  493.     delete point;
  494.     node = node->Next();
  495.   }
  496.   m_attachmentPoints.Clear();
  497. }
  498.  
  499. void wxShape::ClearText(int regionId)
  500. {
  501.   if (regionId == 0)
  502.   {
  503.     m_text.DeleteContents(TRUE);
  504.     m_text.Clear();
  505.     m_text.DeleteContents(FALSE);
  506.   }
  507.   wxNode *node = m_regions.Nth(regionId);
  508.   if (!node)
  509.     return;
  510.   wxShapeRegion *region = (wxShapeRegion *)node->Data();
  511.   region->ClearText();
  512. }
  513.  
  514. void wxShape::ClearRegions()
  515. {
  516.   wxNode *node = m_regions.First();
  517.   while (node)
  518.   {
  519.     wxShapeRegion *region = (wxShapeRegion *)node->Data();
  520.     wxNode *next = node->Next();
  521.     delete region;
  522.     delete node;
  523.     node = next;
  524.   }
  525. }
  526.  
  527. void wxShape::AddRegion(wxShapeRegion *region)
  528. {
  529.   m_regions.Append(region);
  530. }
  531.  
  532. void wxShape::SetDefaultRegionSize()
  533. {
  534.   wxNode *node = m_regions.First();
  535.   if (!node) return;
  536.   wxShapeRegion *region = (wxShapeRegion *)node->Data();
  537.   double w, h;
  538.   GetBoundingBoxMin(&w, &h);
  539.   region->SetSize(w, h);
  540. }
  541.  
  542. bool wxShape::HitTest(double x, double y, int *attachment, double *distance)
  543. {
  544. //  if (!sensitive)
  545. //    return FALSE;
  546.  
  547.   double width = 0.0, height = 0.0;
  548.   GetBoundingBoxMin(&width, &height);
  549.   if (fabs(width) < 4.0) width = 4.0;
  550.   if (fabs(height) < 4.0) height = 4.0;
  551.  
  552.   width += (double)4.0; height += (double)4.0; // Allowance for inaccurate mousing
  553.  
  554.   double left = (double)(m_xpos - (width/2.0));
  555.   double top = (double)(m_ypos - (height/2.0));
  556.   double right = (double)(m_xpos + (width/2.0));
  557.   double bottom = (double)(m_ypos + (height/2.0));
  558.  
  559.   int nearest_attachment = 0;
  560.  
  561.   // If within the bounding box, check the attachment points
  562.   // within the object.
  563.  
  564.   if (x >= left && x <= right && y >= top && y <= bottom)
  565.   {
  566.     int n = GetNumberOfAttachments();
  567.     double nearest = 999999.0;
  568.  
  569.     // GetAttachmentPosition[Edge] takes a logical attachment position,
  570.     // i.e. if it's rotated through 90%, position 0 is East-facing.
  571.  
  572.     for (int i = 0; i < n; i++)
  573.     {
  574.       double xp, yp;
  575.       if (GetAttachmentPositionEdge(i, &xp, &yp))
  576.       {
  577.         double l = (double)sqrt(((xp - x) * (xp - x)) +
  578.                    ((yp - y) * (yp - y)));
  579.  
  580.         if (l < nearest)
  581.         {
  582.           nearest = l;
  583.           nearest_attachment = i;
  584.         }
  585.       }
  586.     }
  587.     *attachment = nearest_attachment;
  588.     *distance = nearest;
  589.     return TRUE;
  590.   }
  591.   else return FALSE;
  592. }
  593.  
  594. // Format a text string according to the region size, adding
  595. // strings with positions to region text list
  596.  
  597. static bool GraphicsInSizeToContents = FALSE; // Infinite recursion elimination
  598. void wxShape::FormatText(wxDC& dc, const wxString& s, int i)
  599. {
  600.   double w, h;
  601.   ClearText(i);
  602.  
  603.   if (m_regions.Number() < 1)
  604.     return;
  605.   wxNode *node = m_regions.Nth(i);
  606.   if (!node)
  607.     return;
  608.  
  609.   wxShapeRegion *region = (wxShapeRegion *)node->Data();
  610.   region->SetText(s);
  611.   dc.SetFont(* region->GetFont());
  612.  
  613.   region->GetSize(&w, &h);
  614.  
  615.   wxStringList *stringList = oglFormatText(dc, s, (w-5), (h-5), region->GetFormatMode());
  616.   node = stringList->First();
  617.   while (node)
  618.   {
  619.     char *s = (char *)node->Data();
  620.     wxShapeTextLine *line = new wxShapeTextLine(0.0, 0.0, s);
  621.     region->GetFormattedText().Append((wxObject *)line);
  622.     node = node->Next();
  623.   }
  624.   delete stringList;
  625.   double actualW = w;
  626.   double actualH = h;
  627.   // Don't try to resize an object with more than one image (this case should be dealt
  628.   // with by overriden handlers)
  629.   if ((region->GetFormatMode() & FORMAT_SIZE_TO_CONTENTS) &&
  630.       (region->GetFormattedText().Number() > 0) &&
  631.       (m_regions.Number() == 1) && !GraphicsInSizeToContents)
  632.   {
  633.     oglGetCentredTextExtent(dc, &(region->GetFormattedText()), m_xpos, m_ypos, w, h, &actualW, &actualH);
  634.     if ((actualW+m_textMarginX != w ) || (actualH+m_textMarginY != h))
  635.     {
  636.       // If we are a descendant of a composite, must make sure the composite gets
  637.       // resized properly
  638.       wxShape *topAncestor = GetTopAncestor();
  639.  
  640.       if (topAncestor != this)
  641.       {
  642.         // Make sure we don't recurse infinitely
  643.         GraphicsInSizeToContents = TRUE;
  644.  
  645.         wxCompositeShape *composite = (wxCompositeShape *)topAncestor;
  646.         composite->Erase(dc);
  647.         SetSize(actualW+m_textMarginX, actualH+m_textMarginY);
  648.         Move(dc, m_xpos, m_ypos);
  649.         composite->CalculateSize();
  650.         if (composite->Selected())
  651.         {
  652.           composite->DeleteControlPoints(& dc);
  653.           composite->MakeControlPoints();
  654.           composite->MakeMandatoryControlPoints();
  655.         }
  656.         // Where infinite recursion might happen if we didn't stop it
  657.         composite->Draw(dc);
  658.  
  659.         GraphicsInSizeToContents = FALSE;
  660.       }
  661.       else
  662.       {
  663.         Erase(dc);
  664.         SetSize(actualW+m_textMarginX, actualH+m_textMarginY);
  665.         Move(dc, m_xpos, m_ypos);
  666.       }
  667.       SetSize(actualW+m_textMarginX, actualH+m_textMarginY);
  668.       Move(dc, m_xpos, m_ypos);
  669.       EraseContents(dc);
  670.     }
  671.   }
  672.   oglCentreText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, actualW, actualH, region->GetFormatMode());
  673.   m_formatted = TRUE;
  674. }
  675.  
  676. void wxShape::Recentre(wxDC& dc)
  677. {
  678.   double w, h;
  679.   GetBoundingBoxMin(&w, &h);
  680.  
  681.   int noRegions = m_regions.Number();
  682.   for (int i = 0; i < noRegions; i++)
  683.   {
  684.     wxNode *node = m_regions.Nth(i);
  685.     if (node)
  686.     {
  687.       wxShapeRegion *region = (wxShapeRegion *)node->Data();
  688.       oglCentreText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, w, h, region->GetFormatMode());
  689.     }
  690.   }
  691. }
  692.  
  693. bool wxShape::GetPerimeterPoint(double x1, double y1,
  694.                                      double x2, double y2,
  695.                                      double *x3, double *y3)
  696. {
  697.   return FALSE;
  698. }
  699.  
  700. void wxShape::SetPen(wxPen *the_pen)
  701. {
  702.   m_pen = the_pen;
  703. }
  704.  
  705. void wxShape::SetBrush(wxBrush *the_brush)
  706. {
  707.   m_brush = the_brush;
  708. }
  709.  
  710. // Get the top-most (non-division) ancestor, or self
  711. wxShape *wxShape::GetTopAncestor()
  712. {
  713.   if (!GetParent())
  714.     return this;
  715.  
  716.   if (GetParent()->IsKindOf(CLASSINFO(wxDivisionShape)))
  717.     return this;
  718.   else return GetParent()->GetTopAncestor();
  719. }
  720.  
  721. /*
  722.  * Region functions
  723.  *
  724.  */
  725. void wxShape::SetFont(wxFont *the_font, int regionId)
  726. {
  727.   m_font = the_font;
  728.   wxNode *node = m_regions.Nth(regionId);
  729.   if (!node)
  730.     return;
  731.   wxShapeRegion *region = (wxShapeRegion *)node->Data();
  732.   region->SetFont(the_font);
  733. }
  734.  
  735. wxFont *wxShape::GetFont(int n) const
  736. {
  737.   wxNode *node = m_regions.Nth(n);
  738.   if (!node)
  739.     return NULL;
  740.   wxShapeRegion *region = (wxShapeRegion *)node->Data();
  741.   return region->GetFont();
  742. }
  743.  
  744. void wxShape::SetFormatMode(int mode, int regionId)
  745. {
  746.   wxNode *node = m_regions.Nth(regionId);
  747.   if (!node)
  748.     return;
  749.   wxShapeRegion *region = (wxShapeRegion *)node->Data();
  750.   region->SetFormatMode(mode);
  751. }
  752.  
  753. int wxShape::GetFormatMode(int regionId) const
  754. {
  755.   wxNode *node = m_regions.Nth(regionId);
  756.   if (!node)
  757.     return 0;
  758.   wxShapeRegion *region = (wxShapeRegion *)node->Data();
  759.   return region->GetFormatMode();
  760. }
  761.  
  762. void wxShape::SetTextColour(const wxString& the_colour, int regionId)
  763. {
  764.   wxColour *wxcolour = wxTheColourDatabase->FindColour(the_colour);
  765.   m_textColour = wxcolour;
  766.   m_textColourName = the_colour;
  767.  
  768.   wxNode *node = m_regions.Nth(regionId);
  769.   if (!node)
  770.     return;
  771.   wxShapeRegion *region = (wxShapeRegion *)node->Data();
  772.   region->SetColour(the_colour);
  773. }
  774.  
  775. wxString wxShape::GetTextColour(int regionId) const
  776. {
  777.   wxNode *node = m_regions.Nth(regionId);
  778.   if (!node)
  779.     return wxString("");
  780.   wxShapeRegion *region = (wxShapeRegion *)node->Data();
  781.   return region->GetColour();
  782. }
  783.  
  784. void wxShape::SetRegionName(const wxString& name, int regionId)
  785. {
  786.   wxNode *node = m_regions.Nth(regionId);
  787.   if (!node)
  788.     return;
  789.   wxShapeRegion *region = (wxShapeRegion *)node->Data();
  790.   region->SetName(name);
  791. }
  792.  
  793. wxString wxShape::GetRegionName(int regionId)
  794. {
  795.   wxNode *node = m_regions.Nth(regionId);
  796.   if (!node)
  797.     return wxString("");
  798.   wxShapeRegion *region = (wxShapeRegion *)node->Data();
  799.   return region->GetName();
  800. }
  801.  
  802. int wxShape::GetRegionId(const wxString& name)
  803. {
  804.   wxNode *node = m_regions.First();
  805.   int i = 0;
  806.   while (node)
  807.   {
  808.     wxShapeRegion *region = (wxShapeRegion *)node->Data();
  809.     if (region->GetName() == name)
  810.       return i;
  811.     node = node->Next();
  812.     i ++;
  813.   }
  814.   return -1;
  815. }
  816.  
  817. // Name all m_regions in all subimages recursively.
  818. void wxShape::NameRegions(const wxString& parentName)
  819. {
  820.   int n = GetNumberOfTextRegions();
  821.   wxString buff;
  822.   for (int i = 0; i < n; i++)
  823.   {
  824.     if (parentName.Length() > 0)
  825.       buff << parentName << "." << i;
  826.     else
  827.       buff << i;
  828.     SetRegionName(buff, i);
  829.   }
  830.   wxNode *node = m_children.First();
  831.   int j = 0;
  832.   while (node)
  833.   {
  834.     buff.Empty();
  835.     wxShape *child = (wxShape *)node->Data();
  836.     if (parentName.Length() > 0)
  837.       buff << parentName << "." << j;
  838.     else
  839.       buff << j;
  840.     child->NameRegions(buff);
  841.     node = node->Next();
  842.     j ++;
  843.   }
  844. }
  845.  
  846. // Get a region by name, possibly looking recursively into composites.
  847. wxShape *wxShape::FindRegion(const wxString& name, int *regionId)
  848. {
  849.   int id = GetRegionId(name);
  850.   if (id > -1)
  851.   {
  852.     *regionId = id;
  853.     return this;
  854.   }
  855.  
  856.   wxNode *node = m_children.First();
  857.   while (node)
  858.   {
  859.     wxShape *child = (wxShape *)node->Data();
  860.     wxShape *actualImage = child->FindRegion(name, regionId);
  861.     if (actualImage)
  862.       return actualImage;
  863.     node = node->Next();
  864.   }
  865.   return NULL;
  866. }
  867.  
  868. // Finds all region names for this image (composite or simple).
  869. // Supply empty string list.
  870. void wxShape::FindRegionNames(wxStringList& list)
  871. {
  872.   int n = GetNumberOfTextRegions();
  873.   for (int i = 0; i < n; i++)
  874.   {
  875.     wxString name(GetRegionName(i));
  876.     list.Add(name);
  877.   }
  878.  
  879.   wxNode *node = m_children.First();
  880.   while (node)
  881.   {
  882.     wxShape *child = (wxShape *)node->Data();
  883.     child->FindRegionNames(list);
  884.     node = node->Next();
  885.   }
  886. }
  887.  
  888. void wxShape::AssignNewIds()
  889. {
  890. //  if (m_id == 0)
  891.   m_id = wxNewId();
  892.   wxNode *node = m_children.First();
  893.   while (node)
  894.   {
  895.     wxShape *child = (wxShape *)node->Data();
  896.     child->AssignNewIds();
  897.     node = node->Next();
  898.   }
  899. }
  900.  
  901. void wxShape::OnDraw(wxDC& dc)
  902. {
  903. }
  904.  
  905. void wxShape::OnMoveLinks(wxDC& dc)
  906. {
  907.   // Want to set the ends of all attached links
  908.   // to point to/from this object
  909.  
  910.   wxNode *current = m_lines.First();
  911.   while (current)
  912.   {
  913.     wxLineShape *line = (wxLineShape *)current->Data();
  914.     line->GetEventHandler()->OnMoveLink(dc);
  915.     current = current->Next();
  916.   }
  917. }
  918.  
  919.  
  920. void wxShape::OnDrawContents(wxDC& dc)
  921. {
  922.   double bound_x, bound_y;
  923.   GetBoundingBoxMin(&bound_x, &bound_y);
  924.     if (m_regions.Number() < 1) return;
  925.  
  926.     if (m_pen) dc.SetPen(* m_pen);
  927.  
  928.     wxShapeRegion *region = (wxShapeRegion *)m_regions.First()->Data();
  929.     if (region->GetFont()) dc.SetFont(* region->GetFont());
  930.  
  931.     dc.SetTextForeground(* (region->GetActualColourObject()));
  932.     dc.SetBackgroundMode(wxTRANSPARENT);
  933.     if (!m_formatted)
  934.     {
  935.       oglCentreText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, bound_x, bound_y, region->GetFormatMode());
  936.       m_formatted = TRUE;
  937.     }
  938.     if (!GetDisableLabel())
  939.     {
  940.       oglDrawFormattedText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, bound_x, bound_y, region->GetFormatMode());
  941.     }
  942. }
  943.  
  944. void wxShape::DrawContents(wxDC& dc)
  945. {
  946.   GetEventHandler()->OnDrawContents(dc);
  947. }
  948.  
  949. void wxShape::OnSize(double x, double y)
  950. {
  951. }
  952.  
  953. bool wxShape::OnMovePre(wxDC& dc, double x, double y, double old_x, double old_y, bool display)
  954. {
  955.   return TRUE;
  956. }
  957.  
  958. void wxShape::OnMovePost(wxDC& dc, double x, double y, double old_x, double old_y, bool display)
  959. {
  960. }
  961.  
  962. void wxShape::OnErase(wxDC& dc)
  963. {
  964.   if (!m_visible)
  965.     return;
  966.  
  967.   // Erase links
  968.   wxNode *current = m_lines.First();
  969.   while (current)
  970.   {
  971.     wxLineShape *line = (wxLineShape *)current->Data();
  972.     line->GetEventHandler()->OnErase(dc);
  973.     current = current->Next();
  974.   }
  975.   GetEventHandler()->OnEraseContents(dc);
  976. }
  977.  
  978. void wxShape::OnEraseContents(wxDC& dc)
  979. {
  980.   if (!m_visible)
  981.     return;
  982.  
  983.   double maxX, maxY, minX, minY;
  984.   double xp = GetX();
  985.   double yp = GetY();
  986.   GetBoundingBoxMin(&minX, &minY);
  987.   GetBoundingBoxMax(&maxX, &maxY);
  988.   double topLeftX = (double)(xp - (maxX / 2.0) - 2.0);
  989.   double topLeftY = (double)(yp - (maxY / 2.0) - 2.0);
  990.  
  991.     int penWidth = 0;
  992.     if (m_pen)
  993.       penWidth = m_pen->GetWidth();
  994.  
  995.     dc.SetPen(GetBackgroundPen());
  996.     dc.SetBrush(GetBackgroundBrush());
  997.  
  998.     dc.DrawRectangle(WXROUND(topLeftX - penWidth), WXROUND(topLeftY - penWidth),
  999.                       WXROUND(maxX + penWidth*2.0 + 4.0), WXROUND(maxY + penWidth*2.0 + 4.0));
  1000. }
  1001.  
  1002. void wxShape::EraseLinks(wxDC& dc, int attachment, bool recurse)
  1003. {
  1004.   if (!m_visible)
  1005.     return;
  1006.  
  1007.   wxNode *current = m_lines.First();
  1008.   while (current)
  1009.   {
  1010.     wxLineShape *line = (wxLineShape *)current->Data();
  1011.     if (attachment == -1 || ((line->GetTo() == this && line->GetAttachmentTo() == attachment) ||
  1012.                              (line->GetFrom() == this && line->GetAttachmentFrom() == attachment)))
  1013.       line->GetEventHandler()->OnErase(dc);
  1014.     current = current->Next();
  1015.   }
  1016.   if (recurse)
  1017.   {
  1018.     wxNode *node = m_children.First();
  1019.     while (node)
  1020.     {
  1021.       wxShape *child = (wxShape *)node->Data();
  1022.       child->EraseLinks(dc, attachment, recurse);
  1023.       node = node->Next();
  1024.     }
  1025.   }
  1026. }
  1027.  
  1028. void wxShape::DrawLinks(wxDC& dc, int attachment, bool recurse)
  1029. {
  1030.   if (!m_visible)
  1031.     return;
  1032.  
  1033.   wxNode *current = m_lines.First();
  1034.   while (current)
  1035.   {
  1036.     wxLineShape *line = (wxLineShape *)current->Data();
  1037.     if (attachment == -1 ||
  1038.         (line->GetTo() == this && line->GetAttachmentTo() == attachment) ||
  1039.         (line->GetFrom() == this && line->GetAttachmentFrom() == attachment))
  1040.       line->Draw(dc);
  1041.     current = current->Next();
  1042.   }
  1043.   if (recurse)
  1044.   {
  1045.     wxNode *node = m_children.First();
  1046.     while (node)
  1047.     {
  1048.       wxShape *child = (wxShape *)node->Data();
  1049.       child->DrawLinks(dc, attachment, recurse);
  1050.       node = node->Next();
  1051.     }
  1052.   }
  1053. }
  1054.  
  1055. // Returns TRUE if pt1 <= pt2 in the sense that one point comes before another on an
  1056. // edge of the shape.
  1057. // attachmentPoint is the attachment point (= side) in question.
  1058.  
  1059. // This is the default, rectangular implementation.
  1060. bool wxShape::AttachmentSortTest(int attachmentPoint, const wxRealPoint& pt1, const wxRealPoint& pt2)
  1061. {
  1062.     int physicalAttachment = LogicalToPhysicalAttachment(attachmentPoint);
  1063.     switch (physicalAttachment)
  1064.     {
  1065.         case 0:
  1066.         case 2:
  1067.         {
  1068.           return (pt1.x <= pt2.x) ;
  1069.           break;
  1070.         }
  1071.         case 1:
  1072.         case 3:
  1073.         {
  1074.           return (pt1.y <= pt2.y) ;
  1075.           break;
  1076.         }
  1077.     }
  1078.  
  1079.     return FALSE;
  1080. }
  1081.  
  1082. bool wxShape::MoveLineToNewAttachment(wxDC& dc, wxLineShape *to_move,
  1083.                                        double x, double y)
  1084. {
  1085.   if (GetAttachmentMode() == ATTACHMENT_MODE_NONE)
  1086.       return FALSE;
  1087.  
  1088.   int newAttachment, oldAttachment;
  1089.   double distance;
  1090.  
  1091.   // Is (x, y) on this object? If so, find the new attachment point
  1092.   // the user has moved the point to
  1093.   bool hit = HitTest(x, y, &newAttachment, &distance);
  1094.   if (!hit)
  1095.     return FALSE;
  1096.  
  1097.   EraseLinks(dc);
  1098.  
  1099.   if (to_move->GetTo() == this)
  1100.     oldAttachment = to_move->GetAttachmentTo();
  1101.   else
  1102.     oldAttachment = to_move->GetAttachmentFrom();
  1103.  
  1104.   // The links in a new ordering.
  1105.   wxList newOrdering;
  1106.  
  1107.   // First, add all links to the new list.
  1108.   wxNode *node = m_lines.First();
  1109.   while (node)
  1110.   {
  1111.     newOrdering.Append(node->Data());
  1112.     node = node->Next();
  1113.   }
  1114.  
  1115.   // Delete the line object from the list of links; we're going to move
  1116.   // it to another position in the list
  1117.   newOrdering.DeleteObject(to_move);
  1118.  
  1119.   double old_x = (double) -99999.9;
  1120.   double old_y = (double) -99999.9;
  1121.  
  1122.   node = newOrdering.First();
  1123.   bool found = FALSE;
  1124.  
  1125.   while (!found && node)
  1126.   {
  1127.     wxLineShape *line = (wxLineShape *)node->Data();
  1128.     if ((line->GetTo() == this && oldAttachment == line->GetAttachmentTo()) ||
  1129.         (line->GetFrom() == this && oldAttachment == line->GetAttachmentFrom()))
  1130.     {
  1131.       double startX, startY, endX, endY;
  1132.       double xp, yp;
  1133.       line->GetEnds(&startX, &startY, &endX, &endY);
  1134.       if (line->GetTo() == this)
  1135.       {
  1136.         xp = endX;
  1137.         yp = endY;
  1138.       } else
  1139.       {
  1140.         xp = startX;
  1141.         yp = startY;
  1142.       }
  1143.  
  1144.       wxRealPoint thisPoint(xp, yp);
  1145.       wxRealPoint lastPoint(old_x, old_y);
  1146.       wxRealPoint newPoint(x, y);
  1147.  
  1148.       if (AttachmentSortTest(newAttachment, newPoint, thisPoint) && AttachmentSortTest(newAttachment, lastPoint, newPoint))
  1149.       {
  1150.         found = TRUE;
  1151.         newOrdering.Insert(node, to_move);
  1152.       }
  1153.  
  1154.       old_x = xp;
  1155.       old_y = yp;
  1156.     }
  1157.     node = node->Next();
  1158.   }
  1159.  
  1160.   if (!found)
  1161.     newOrdering.Append(to_move);
  1162.  
  1163.   GetEventHandler()->OnChangeAttachment(newAttachment, to_move, newOrdering);
  1164.  
  1165.   return TRUE;
  1166. }
  1167.  
  1168. void wxShape::OnChangeAttachment(int attachment, wxLineShape* line, wxList& ordering)
  1169. {
  1170.     if (line->GetTo() == this)
  1171.         line->SetAttachmentTo(attachment);
  1172.     else
  1173.         line->SetAttachmentFrom(attachment);
  1174.  
  1175.     ApplyAttachmentOrdering(ordering);
  1176.  
  1177.     wxClientDC dc(GetCanvas());
  1178.     GetCanvas()->PrepareDC(dc);
  1179.  
  1180.     MoveLinks(dc);
  1181.  
  1182.     if (!GetCanvas()->GetQuickEditMode()) GetCanvas()->Redraw(dc);
  1183. }
  1184.  
  1185. // Reorders the lines according to the given list.
  1186. void wxShape::ApplyAttachmentOrdering(wxList& linesToSort)
  1187. {
  1188.   // This is a temporary store of all the lines.
  1189.   wxList linesStore;
  1190.  
  1191.   wxNode *node = m_lines.First();
  1192.   while (node)
  1193.   {
  1194.     wxLineShape *line = (wxLineShape *)node->Data();
  1195.     linesStore.Append(line);
  1196.     node = node->Next();;
  1197.   }
  1198.  
  1199.   m_lines.Clear();
  1200.  
  1201.   node = linesToSort.First();
  1202.   while (node)
  1203.   {
  1204.     wxLineShape *line = (wxLineShape *)node->Data();
  1205.     if (linesStore.Member(line))
  1206.     {
  1207.       // Done this one
  1208.       linesStore.DeleteObject(line);
  1209.       m_lines.Append(line);
  1210.     }
  1211.     node = node->Next();
  1212.   }
  1213.  
  1214.   // Now add any lines that haven't been listed in linesToSort.
  1215.   node = linesStore.First();
  1216.   while (node)
  1217.   {
  1218.     wxLineShape *line = (wxLineShape *)node->Data();
  1219.     m_lines.Append(line);
  1220.     node = node->Next();
  1221.   }
  1222. }
  1223.  
  1224. // Reorders the lines coming into the node image at this attachment
  1225. // position, in the order in which they appear in linesToSort.
  1226. // Any remaining lines not in the list will be added to the end.
  1227. void wxShape::SortLines(int attachment, wxList& linesToSort)
  1228. {
  1229.   // This is a temporary store of all the lines at this attachment
  1230.   // point. We'll tick them off as we've processed them.
  1231.   wxList linesAtThisAttachment;
  1232.  
  1233.   wxNode *node = m_lines.First();
  1234.   while (node)
  1235.   {
  1236.     wxLineShape *line = (wxLineShape *)node->Data();
  1237.     wxNode *next = node->Next();
  1238.     if ((line->GetTo() == this && line->GetAttachmentTo() == attachment) ||
  1239.         (line->GetFrom() == this && line->GetAttachmentFrom() == attachment))
  1240.     {
  1241.       linesAtThisAttachment.Append(line);
  1242.       delete node;
  1243.       node = next;
  1244.     }
  1245.     else node = node->Next();
  1246.   }
  1247.  
  1248.   node = linesToSort.First();
  1249.   while (node)
  1250.   {
  1251.     wxLineShape *line = (wxLineShape *)node->Data();
  1252.     if (linesAtThisAttachment.Member(line))
  1253.     {
  1254.       // Done this one
  1255.       linesAtThisAttachment.DeleteObject(line);
  1256.       m_lines.Append(line);
  1257.     }
  1258.     node = node->Next();
  1259.   }
  1260.  
  1261.   // Now add any lines that haven't been listed in linesToSort.
  1262.   node = linesAtThisAttachment.First();
  1263.   while (node)
  1264.   {
  1265.     wxLineShape *line = (wxLineShape *)node->Data();
  1266.     m_lines.Append(line);
  1267.     node = node->Next();
  1268.   }
  1269. }
  1270.  
  1271. void wxShape::OnHighlight(wxDC& dc)
  1272. {
  1273. }
  1274.  
  1275. void wxShape::OnLeftClick(double x, double y, int keys, int attachment)
  1276. {
  1277.   if ((m_sensitivity & OP_CLICK_LEFT) != OP_CLICK_LEFT)
  1278.   {
  1279.     attachment = 0;
  1280.     double dist;
  1281.     if (m_parent)
  1282.     {
  1283.       m_parent->HitTest(x, y, &attachment, &dist);
  1284.       m_parent->GetEventHandler()->OnLeftClick(x, y, keys, attachment);
  1285.     }
  1286.     return;
  1287.   }
  1288. }
  1289.  
  1290. void wxShape::OnRightClick(double x, double y, int keys, int attachment)
  1291. {
  1292.   if ((m_sensitivity & OP_CLICK_RIGHT) != OP_CLICK_RIGHT)
  1293.   {
  1294.     attachment = 0;
  1295.     double dist;
  1296.     if (m_parent)
  1297.     {
  1298.       m_parent->HitTest(x, y, &attachment, &dist);
  1299.       m_parent->GetEventHandler()->OnRightClick(x, y, keys, attachment);
  1300.     }
  1301.     return;
  1302.   }
  1303. }
  1304.  
  1305. double DragOffsetX = 0.0;
  1306. double DragOffsetY = 0.0;
  1307.  
  1308. void wxShape::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
  1309. {
  1310.   if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT)
  1311.   {
  1312.     attachment = 0;
  1313.     double dist;
  1314.     if (m_parent)
  1315.     {
  1316.       m_parent->HitTest(x, y, &attachment, &dist);
  1317.       m_parent->GetEventHandler()->OnDragLeft(draw, x, y, keys, attachment);
  1318.     }
  1319.     return;
  1320.   }
  1321.  
  1322.   wxClientDC dc(GetCanvas());
  1323.   GetCanvas()->PrepareDC(dc);
  1324.  
  1325.   dc.SetLogicalFunction(OGLRBLF);
  1326.  
  1327.   wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
  1328.   dc.SetPen(dottedPen);
  1329.   dc.SetBrush(* wxTRANSPARENT_BRUSH);
  1330.  
  1331.   double xx, yy;
  1332.   xx = x + DragOffsetX;
  1333.   yy = y + DragOffsetY;
  1334.  
  1335.   m_canvas->Snap(&xx, &yy);
  1336. //  m_xpos = xx; m_ypos = yy;
  1337.   double w, h;
  1338.   GetBoundingBoxMax(&w, &h);
  1339.   GetEventHandler()->OnDrawOutline(dc, xx, yy, w, h);
  1340. }
  1341.  
  1342. void wxShape::OnBeginDragLeft(double x, double y, int keys, int attachment)
  1343. {
  1344.   if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT)
  1345.   {
  1346.     attachment = 0;
  1347.     double dist;
  1348.     if (m_parent)
  1349.     {
  1350.       m_parent->HitTest(x, y, &attachment, &dist);
  1351.       m_parent->GetEventHandler()->OnBeginDragLeft(x, y, keys, attachment);
  1352.     }
  1353.     return;
  1354.   }
  1355.  
  1356.   DragOffsetX = m_xpos - x;
  1357.   DragOffsetY = m_ypos - y;
  1358.  
  1359.   wxClientDC dc(GetCanvas());
  1360.   GetCanvas()->PrepareDC(dc);
  1361.  
  1362.   // New policy: don't erase shape until end of drag.
  1363. //  Erase(dc);
  1364.  
  1365.   double xx, yy;
  1366.   xx = x + DragOffsetX;
  1367.   yy = y + DragOffsetY;
  1368.   m_canvas->Snap(&xx, &yy);
  1369. //  m_xpos = xx; m_ypos = yy;
  1370.   dc.SetLogicalFunction(OGLRBLF);
  1371.  
  1372.   wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
  1373.   dc.SetPen(dottedPen);
  1374.   dc.SetBrush((* wxTRANSPARENT_BRUSH));
  1375.  
  1376.   double w, h;
  1377.   GetBoundingBoxMax(&w, &h);
  1378.   GetEventHandler()->OnDrawOutline(dc, xx, yy, w, h);
  1379.   m_canvas->CaptureMouse();
  1380. }
  1381.  
  1382. void wxShape::OnEndDragLeft(double x, double y, int keys, int attachment)
  1383. {
  1384.   m_canvas->ReleaseMouse();
  1385.   if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT)
  1386.   {
  1387.     attachment = 0;
  1388.     double dist;
  1389.     if (m_parent)
  1390.     {
  1391.       m_parent->HitTest(x, y, &attachment, &dist);
  1392.       m_parent->GetEventHandler()->OnEndDragLeft(x, y, keys, attachment);
  1393.     }
  1394.     return;
  1395.   }
  1396.  
  1397.   wxClientDC dc(GetCanvas());
  1398.   GetCanvas()->PrepareDC(dc);
  1399.  
  1400.   dc.SetLogicalFunction(wxCOPY);
  1401.  
  1402.   double xx = x + DragOffsetX;
  1403.   double yy = y + DragOffsetY;
  1404.   m_canvas->Snap(&xx, &yy);
  1405. //  canvas->Snap(&m_xpos, &m_ypos);
  1406.  
  1407.   // New policy: erase shape at end of drag.
  1408.   Erase(dc);
  1409.  
  1410.   Move(dc, xx, yy);
  1411.   if (m_canvas && !m_canvas->GetQuickEditMode()) m_canvas->Redraw(dc);
  1412. }
  1413.  
  1414. void wxShape::OnDragRight(bool draw, double x, double y, int keys, int attachment)
  1415. {
  1416.   if ((m_sensitivity & OP_DRAG_RIGHT) != OP_DRAG_RIGHT)
  1417.   {
  1418.     attachment = 0;
  1419.     double dist;
  1420.     if (m_parent)
  1421.     {
  1422.       m_parent->HitTest(x, y, &attachment, &dist);
  1423.       m_parent->GetEventHandler()->OnDragRight(draw, x, y, keys, attachment);
  1424.     }
  1425.     return;
  1426.   }
  1427. }
  1428.  
  1429. void wxShape::OnBeginDragRight(double x, double y, int keys, int attachment)
  1430. {
  1431.   if ((m_sensitivity & OP_DRAG_RIGHT) != OP_DRAG_RIGHT)
  1432.   {
  1433.     attachment = 0;
  1434.     double dist;
  1435.     if (m_parent)
  1436.     {
  1437.       m_parent->HitTest(x, y, &attachment, &dist);
  1438.       m_parent->GetEventHandler()->OnBeginDragRight(x, y, keys, attachment);
  1439.     }
  1440.     return;
  1441.   }
  1442. }
  1443.  
  1444. void wxShape::OnEndDragRight(double x, double y, int keys, int attachment)
  1445. {
  1446.   if ((m_sensitivity & OP_DRAG_RIGHT) != OP_DRAG_RIGHT)
  1447.   {
  1448.     attachment = 0;
  1449.     double dist;
  1450.     if (m_parent)
  1451.     {
  1452.       m_parent->HitTest(x, y, &attachment, &dist);
  1453.       m_parent->GetEventHandler()->OnEndDragRight(x, y, keys, attachment);
  1454.     }
  1455.     return;
  1456.   }
  1457. }
  1458.  
  1459. void wxShape::OnDrawOutline(wxDC& dc, double x, double y, double w, double h)
  1460. {
  1461.   double top_left_x = (double)(x - w/2.0);
  1462.   double top_left_y = (double)(y - h/2.0);
  1463.   double top_right_x = (double)(top_left_x + w);
  1464.   double top_right_y = (double)top_left_y;
  1465.   double bottom_left_x = (double)top_left_x;
  1466.   double bottom_left_y = (double)(top_left_y + h);
  1467.   double bottom_right_x = (double)top_right_x;
  1468.   double bottom_right_y = (double)bottom_left_y;
  1469.  
  1470.   wxPoint points[5];
  1471.   points[0].x = WXROUND(top_left_x); points[0].y = WXROUND(top_left_y);
  1472.   points[1].x = WXROUND(top_right_x); points[1].y = WXROUND(top_right_y);
  1473.   points[2].x = WXROUND(bottom_right_x); points[2].y = WXROUND(bottom_right_y);
  1474.   points[3].x = WXROUND(bottom_left_x); points[3].y = WXROUND(bottom_left_y);
  1475.   points[4].x = WXROUND(top_left_x); points[4].y = WXROUND(top_left_y);
  1476.  
  1477.   dc.DrawLines(5, points);
  1478. }
  1479.  
  1480. void wxShape::Attach(wxShapeCanvas *can)
  1481. {
  1482.   m_canvas = can;
  1483. }
  1484.  
  1485. void wxShape::Detach()
  1486. {
  1487.   m_canvas = NULL;
  1488. }
  1489.  
  1490. void wxShape::Move(wxDC& dc, double x, double y, bool display)
  1491. {
  1492.   double old_x = m_xpos;
  1493.   double old_y = m_ypos;
  1494.  
  1495.   if (!GetEventHandler()->OnMovePre(dc, x, y, old_x, old_y, display))
  1496.   {
  1497. //    m_xpos = old_x;
  1498. //    m_ypos = old_y;
  1499.     return;
  1500.   }
  1501.  
  1502.   m_xpos = x; m_ypos = y;
  1503.  
  1504.   ResetControlPoints();
  1505.  
  1506.   if (display)
  1507.     Draw(dc);
  1508.  
  1509.   MoveLinks(dc);
  1510.  
  1511.   GetEventHandler()->OnMovePost(dc, x, y, old_x, old_y, display);
  1512. }
  1513.  
  1514. void wxShape::MoveLinks(wxDC& dc)
  1515. {
  1516.   GetEventHandler()->OnMoveLinks(dc);
  1517. }
  1518.  
  1519.  
  1520. void wxShape::Draw(wxDC& dc)
  1521. {
  1522.   if (m_visible)
  1523.   {
  1524.     GetEventHandler()->OnDraw(dc);
  1525.     GetEventHandler()->OnDrawContents(dc);
  1526.     GetEventHandler()->OnDrawControlPoints(dc);
  1527.     GetEventHandler()->OnDrawBranches(dc);
  1528.   }
  1529. }
  1530.  
  1531. void wxShape::Flash()
  1532. {
  1533.     if (GetCanvas())
  1534.     {
  1535.         wxClientDC dc(GetCanvas());
  1536.         GetCanvas()->PrepareDC(dc);
  1537.  
  1538.         dc.SetLogicalFunction(OGLRBLF);
  1539.         Draw(dc);
  1540.         dc.SetLogicalFunction(wxCOPY);
  1541.         Draw(dc);
  1542.     }
  1543. }
  1544.  
  1545. void wxShape::Show(bool show)
  1546. {
  1547.   m_visible = show;
  1548.   wxNode *node = m_children.First();
  1549.   while (node)
  1550.   {
  1551.     wxShape *image = (wxShape *)node->Data();
  1552.     image->Show(show);
  1553.     node = node->Next();
  1554.   }
  1555. }
  1556.  
  1557. void wxShape::Erase(wxDC& dc)
  1558. {
  1559.   GetEventHandler()->OnErase(dc);
  1560.   GetEventHandler()->OnEraseControlPoints(dc);
  1561.   GetEventHandler()->OnDrawBranches(dc, TRUE);
  1562. }
  1563.  
  1564. void wxShape::EraseContents(wxDC& dc)
  1565. {
  1566.   GetEventHandler()->OnEraseContents(dc);
  1567. }
  1568.  
  1569. void wxShape::AddText(const wxString& string)
  1570. {
  1571.   wxNode *node = m_regions.First();
  1572.   if (!node)
  1573.     return;
  1574.   wxShapeRegion *region = (wxShapeRegion *)node->Data();
  1575.   region->ClearText();
  1576.   wxShapeTextLine *new_line =
  1577.       new wxShapeTextLine(0.0, 0.0, string);
  1578.   region->GetFormattedText().Append(new_line);
  1579.  
  1580.   m_formatted = FALSE;
  1581. }
  1582.  
  1583. void wxShape::SetSize(double x, double y, bool recursive)
  1584. {
  1585.   SetAttachmentSize(x, y);
  1586.   SetDefaultRegionSize();
  1587. }
  1588.  
  1589. void wxShape::SetAttachmentSize(double w, double h)
  1590. {
  1591.   double scaleX;
  1592.   double scaleY;
  1593.   double width, height;
  1594.   GetBoundingBoxMin(&width, &height);
  1595.   if (width == 0.0)
  1596.     scaleX = 1.0;
  1597.   else scaleX = w/width;
  1598.   if (height == 0.0)
  1599.     scaleY = 1.0;
  1600.   else scaleY = h/height;
  1601.  
  1602.   wxNode *node = m_attachmentPoints.First();
  1603.   while (node)
  1604.   {
  1605.     wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
  1606.     point->m_x = (double)(point->m_x * scaleX);
  1607.     point->m_y = (double)(point->m_y * scaleY);
  1608.     node = node->Next();
  1609.   }
  1610. }
  1611.  
  1612. // Add line FROM this object
  1613. void wxShape::AddLine(wxLineShape *line, wxShape *other,
  1614.                             int attachFrom, int attachTo,
  1615.                             // The line ordering
  1616.                             int positionFrom, int positionTo)
  1617. {
  1618.     if (positionFrom == -1)
  1619.     {
  1620.         if (!m_lines.Member(line))
  1621.             m_lines.Append(line);
  1622.     }
  1623.     else
  1624.     {
  1625.         // Don't preserve old ordering if we have new ordering instructions
  1626.         m_lines.DeleteObject(line);
  1627.         if (positionFrom < m_lines.Number())
  1628.         {
  1629.             wxNode* node = m_lines.Nth(positionFrom);
  1630.             m_lines.Insert(node, line);
  1631.         }
  1632.         else
  1633.             m_lines.Append(line);
  1634.     }
  1635.  
  1636.     if (positionTo == -1)
  1637.     {
  1638.         if (!other->m_lines.Member(line))
  1639.             other->m_lines.Append(line);
  1640.     }
  1641.     else
  1642.     {
  1643.         // Don't preserve old ordering if we have new ordering instructions
  1644.         other->m_lines.DeleteObject(line);
  1645.         if (positionTo < other->m_lines.Number())
  1646.         {
  1647.             wxNode* node = other->m_lines.Nth(positionTo);
  1648.             other->m_lines.Insert(node, line);
  1649.         }
  1650.         else
  1651.             other->m_lines.Append(line);
  1652.     }
  1653. #if 0
  1654.     // Wrong: doesn't preserve ordering of shape already linked
  1655.     m_lines.DeleteObject(line);
  1656.     other->m_lines.DeleteObject(line);
  1657.  
  1658.     if (positionFrom == -1)
  1659.         m_lines.Append(line);
  1660.     else
  1661.     {
  1662.         if (positionFrom < m_lines.Number())
  1663.         {
  1664.             wxNode* node = m_lines.Nth(positionFrom);
  1665.             m_lines.Insert(node, line);
  1666.         }
  1667.         else
  1668.             m_lines.Append(line);
  1669.     }
  1670.  
  1671.     if (positionTo == -1)
  1672.         other->m_lines.Append(line);
  1673.     else
  1674.     {
  1675.         if (positionTo < other->m_lines.Number())
  1676.         {
  1677.             wxNode* node = other->m_lines.Nth(positionTo);
  1678.             other->m_lines.Insert(node, line);
  1679.         }
  1680.         else
  1681.             other->m_lines.Append(line);
  1682.     }
  1683. #endif
  1684.  
  1685.     line->SetFrom(this);
  1686.     line->SetTo(other);
  1687.     line->SetAttachments(attachFrom, attachTo);
  1688. }
  1689.  
  1690. void wxShape::RemoveLine(wxLineShape *line)
  1691. {
  1692.   if (line->GetFrom() == this)
  1693.     line->GetTo()->m_lines.DeleteObject(line);
  1694.   else
  1695.    line->GetFrom()->m_lines.DeleteObject(line);
  1696.  
  1697.   m_lines.DeleteObject(line);
  1698. }
  1699.  
  1700. #ifdef PROLOGIO
  1701. void wxShape::WriteAttributes(wxExpr *clause)
  1702. {
  1703.   clause->AddAttributeValueString("type", GetClassInfo()->GetClassName());
  1704.   clause->AddAttributeValue("id", m_id);
  1705.  
  1706.   if (m_pen)
  1707.   {
  1708.     int penWidth = m_pen->GetWidth();
  1709.     int penStyle = m_pen->GetStyle();
  1710.     if (penWidth != 1)
  1711.       clause->AddAttributeValue("pen_width", (long)penWidth);
  1712.     if (penStyle != wxSOLID)
  1713.       clause->AddAttributeValue("pen_style", (long)penStyle);
  1714.  
  1715.     wxString penColour = wxTheColourDatabase->FindName(m_pen->GetColour());
  1716.     if (penColour == "")
  1717.     {
  1718.       wxString hex(oglColourToHex(m_pen->GetColour()));
  1719.       hex = wxString("#") + hex;
  1720.       clause->AddAttributeValueString("pen_colour", hex);
  1721.     }
  1722.     else if (penColour != "BLACK")
  1723.       clause->AddAttributeValueString("pen_colour", penColour);
  1724.   }
  1725.  
  1726.   if (m_brush)
  1727.   {
  1728.     wxString brushColour = wxTheColourDatabase->FindName(m_brush->GetColour());
  1729.  
  1730.     if (brushColour == "")
  1731.     {
  1732.       wxString hex(oglColourToHex(m_brush->GetColour()));
  1733.       hex = wxString("#") + hex;
  1734.       clause->AddAttributeValueString("brush_colour", hex);
  1735.     }
  1736.     else if (brushColour != "WHITE")
  1737.       clause->AddAttributeValueString("brush_colour", brushColour);
  1738.  
  1739.     if (m_brush->GetStyle() != wxSOLID)
  1740.       clause->AddAttributeValue("brush_style", (long)m_brush->GetStyle());
  1741.   }
  1742.  
  1743.   // Output line ids
  1744.  
  1745.   int n_lines = m_lines.Number();
  1746.   if (n_lines > 0)
  1747.   {
  1748.     wxExpr *list = new wxExpr(wxExprList);
  1749.     wxNode *node = m_lines.First();
  1750.     while (node)
  1751.     {
  1752.       wxShape *line = (wxShape *)node->Data();
  1753.       wxExpr *id_expr = new wxExpr(line->GetId());
  1754.       list->Append(id_expr);
  1755.       node = node->Next();
  1756.     }
  1757.     clause->AddAttributeValue("arcs", list);
  1758.   }
  1759.  
  1760.   // Miscellaneous members
  1761.   if (m_attachmentMode != 0)
  1762.     clause->AddAttributeValue("use_attachments", (long)m_attachmentMode);
  1763.   if (m_sensitivity != OP_ALL)
  1764.     clause->AddAttributeValue("sensitivity", (long)m_sensitivity);
  1765.   if (!m_spaceAttachments)
  1766.     clause->AddAttributeValue("space_attachments", (long)m_spaceAttachments);
  1767.   if (m_fixedWidth)
  1768.     clause->AddAttributeValue("fixed_width", (long)m_fixedWidth);
  1769.   if (m_fixedHeight)
  1770.     clause->AddAttributeValue("fixed_height", (long)m_fixedHeight);
  1771.   if (m_shadowMode != SHADOW_NONE)
  1772.     clause->AddAttributeValue("shadow_mode", (long)m_shadowMode);
  1773.   if (m_centreResize != TRUE)
  1774.     clause->AddAttributeValue("centre_resize", (long)0);
  1775.   clause->AddAttributeValue("maintain_aspect_ratio", (long) m_maintainAspectRatio);
  1776.   if (m_highlighted != FALSE)
  1777.     clause->AddAttributeValue("hilite", (long)m_highlighted);
  1778.  
  1779.   if (m_parent) // For composite objects
  1780.     clause->AddAttributeValue("parent", (long)m_parent->GetId());
  1781.  
  1782.   if (m_rotation != 0.0)
  1783.     clause->AddAttributeValue("rotation", m_rotation);
  1784.  
  1785.   if (!this->IsKindOf(CLASSINFO(wxLineShape)))
  1786.   {
  1787.     clause->AddAttributeValue("neck_length", (long) m_branchNeckLength);
  1788.     clause->AddAttributeValue("stem_length", (long) m_branchStemLength);
  1789.     clause->AddAttributeValue("branch_spacing", (long) m_branchSpacing);
  1790.     clause->AddAttributeValue("branch_style", (long) m_branchStyle);
  1791.   }
  1792.  
  1793.   // Write user-defined attachment points, if any
  1794.   if (m_attachmentPoints.Number() > 0)
  1795.   {
  1796.     wxExpr *attachmentList = new wxExpr(wxExprList);
  1797.     wxNode *node = m_attachmentPoints.First();
  1798.     while (node)
  1799.     {
  1800.       wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
  1801.       wxExpr *pointExpr = new wxExpr(wxExprList);
  1802.       pointExpr->Append(new wxExpr((long)point->m_id));
  1803.       pointExpr->Append(new wxExpr(point->m_x));
  1804.       pointExpr->Append(new wxExpr(point->m_y));
  1805.       attachmentList->Append(pointExpr);
  1806.       node = node->Next();
  1807.     }
  1808.     clause->AddAttributeValue("user_attachments", attachmentList);
  1809.   }
  1810.  
  1811.   // Write text regions
  1812.   WriteRegions(clause);
  1813. }
  1814.  
  1815. void wxShape::WriteRegions(wxExpr *clause)
  1816. {
  1817.   // Output regions as region1 = (...), region2 = (...), etc
  1818.   // and formatted text as text1 = (...), text2 = (...) etc.
  1819.   int regionNo = 1;
  1820.   char regionNameBuf[20];
  1821.   char textNameBuf[20];
  1822.   wxNode *node = m_regions.First();
  1823.   while (node)
  1824.   {
  1825.     wxShapeRegion *region = (wxShapeRegion *)node->Data();
  1826.     sprintf(regionNameBuf, "region%d", regionNo);
  1827.     sprintf(textNameBuf, "text%d", regionNo);
  1828.  
  1829.     // Original text and region attributes:
  1830.     // region1 = (regionName regionText x y width height minWidth minHeight proportionX proportionY
  1831.     //            formatMode fontSize fontFamily fontStyle fontWeight textColour)
  1832.     wxExpr *regionExpr = new wxExpr(wxExprList);
  1833.     regionExpr->Append(new wxExpr(wxExprString, region->m_regionName));
  1834.     regionExpr->Append(new wxExpr(wxExprString, region->m_regionText));
  1835.  
  1836.     regionExpr->Append(new wxExpr(region->m_x));
  1837.     regionExpr->Append(new wxExpr(region->m_y));
  1838.     regionExpr->Append(new wxExpr(region->GetWidth()));
  1839.     regionExpr->Append(new wxExpr(region->GetHeight()));
  1840.  
  1841.     regionExpr->Append(new wxExpr(region->m_minWidth));
  1842.     regionExpr->Append(new wxExpr(region->m_minHeight));
  1843.     regionExpr->Append(new wxExpr(region->m_regionProportionX));
  1844.     regionExpr->Append(new wxExpr(region->m_regionProportionY));
  1845.  
  1846.     regionExpr->Append(new wxExpr((long)region->m_formatMode));
  1847.  
  1848.     regionExpr->Append(new wxExpr((long)(region->m_font ? region->m_font->GetPointSize() : 10)));
  1849.     regionExpr->Append(new wxExpr((long)(region->m_font ? region->m_font->GetFamily() : wxDEFAULT)));
  1850.     regionExpr->Append(new wxExpr((long)(region->m_font ? region->m_font->GetStyle() : wxDEFAULT)));
  1851.     regionExpr->Append(new wxExpr((long)(region->m_font ? region->m_font->GetWeight() : wxNORMAL)));
  1852.     regionExpr->Append(new wxExpr(wxExprString, region->m_textColour));
  1853.  
  1854.     // New members for pen colour/style
  1855.     regionExpr->Append(new wxExpr(wxExprString, region->m_penColour));
  1856.     regionExpr->Append(new wxExpr((long)region->m_penStyle));
  1857.  
  1858.     // Formatted text:
  1859.     // text1 = ((x y string) (x y string) ...)
  1860.     wxExpr *textExpr = new wxExpr(wxExprList);
  1861.  
  1862.     wxNode *textNode = region->m_formattedText.First();
  1863.     while (textNode)
  1864.     {
  1865.       wxShapeTextLine *line = (wxShapeTextLine *)textNode->Data();
  1866.       wxExpr *list2 = new wxExpr(wxExprList);
  1867.       list2->Append(new wxExpr(line->GetX()));
  1868.       list2->Append(new wxExpr(line->GetY()));
  1869.       list2->Append(new wxExpr(wxExprString, line->GetText()));
  1870.       textExpr->Append(list2);
  1871.       textNode = textNode->Next();
  1872.     }
  1873.  
  1874.     // Now add both attributes to the clause
  1875.     clause->AddAttributeValue(regionNameBuf, regionExpr);
  1876.     clause->AddAttributeValue(textNameBuf, textExpr);
  1877.  
  1878.     node = node->Next();
  1879.     regionNo ++;
  1880.   }
  1881. }
  1882.  
  1883. void wxShape::ReadAttributes(wxExpr *clause)
  1884. {
  1885.   clause->GetAttributeValue("id", m_id);
  1886.   wxRegisterId(m_id);
  1887.  
  1888.   clause->GetAttributeValue("x", m_xpos);
  1889.   clause->GetAttributeValue("y", m_ypos);
  1890.  
  1891.   // Input text strings (FOR COMPATIBILITY WITH OLD FILES ONLY. SEE REGION CODE BELOW.)
  1892.   ClearText();
  1893.   wxExpr *strings = clause->AttributeValue("text");
  1894.   if (strings && strings->Type() == wxExprList)
  1895.   {
  1896.     m_formatted = TRUE;  // Assume text is formatted unless we prove otherwise
  1897.     wxExpr *node = strings->value.first;
  1898.     while (node)
  1899.     {
  1900.       wxExpr *string_expr = node;
  1901.       double the_x = 0.0;
  1902.       double the_y = 0.0;
  1903.       wxString the_string("");
  1904.  
  1905.       // string_expr can either be a string, or a list of
  1906.       // 3 elements: x, y, and string.
  1907.       if (string_expr->Type() == wxExprString)
  1908.       {
  1909.         the_string = string_expr->StringValue();
  1910.         m_formatted = FALSE;
  1911.       }
  1912.       else if (string_expr->Type() == wxExprList)
  1913.       {
  1914.         wxExpr *first = string_expr->value.first;
  1915.         wxExpr *second = first ? first->next : (wxExpr*) NULL;
  1916.         wxExpr *third = second ? second->next : (wxExpr*) NULL;
  1917.  
  1918.         if (first && second && third &&
  1919.             (first->Type() == wxExprReal || first->Type() == wxExprInteger) &&
  1920.             (second->Type() == wxExprReal || second->Type() == wxExprInteger) &&
  1921.             third->Type() == wxExprString)
  1922.           {
  1923.             if (first->Type() == wxExprReal)
  1924.               the_x = first->RealValue();
  1925.             else the_x = (double)first->IntegerValue();
  1926.  
  1927.             if (second->Type() == wxExprReal)
  1928.               the_y = second->RealValue();
  1929.             else the_y = (double)second->IntegerValue();
  1930.  
  1931.             the_string = third->StringValue();
  1932.           }
  1933.       }
  1934.       wxShapeTextLine *line =
  1935.             new wxShapeTextLine(the_x, the_y, the_string);
  1936.       m_text.Append(line);
  1937.  
  1938.       node = node->next;
  1939.     }
  1940.   }
  1941.  
  1942.   wxString pen_string = "";
  1943.   wxString brush_string = "";
  1944.   int pen_width = 1;
  1945.   int pen_style = wxSOLID;
  1946.   int brush_style = wxSOLID;
  1947.   m_attachmentMode = ATTACHMENT_MODE_NONE;
  1948.  
  1949.   clause->GetAttributeValue("pen_colour", pen_string);
  1950.   clause->GetAttributeValue("text_colour", m_textColourName);
  1951.  
  1952.   SetTextColour(m_textColourName);
  1953.  
  1954.   clause->GetAttributeValue("region_name", m_regionName);
  1955.  
  1956.   clause->GetAttributeValue("brush_colour", brush_string);
  1957.   clause->GetAttributeValue("pen_width", pen_width);
  1958.   clause->GetAttributeValue("pen_style", pen_style);
  1959.   clause->GetAttributeValue("brush_style", brush_style);
  1960.  
  1961.   int iVal = (int) m_attachmentMode;
  1962.   clause->GetAttributeValue("use_attachments", iVal);
  1963.   m_attachmentMode = iVal;
  1964.  
  1965.   clause->GetAttributeValue("sensitivity", m_sensitivity);
  1966.  
  1967.   iVal = (int) m_spaceAttachments;
  1968.   clause->GetAttributeValue("space_attachments", iVal);
  1969.   m_spaceAttachments = (iVal != 0);
  1970.  
  1971.   iVal = (int) m_fixedWidth;
  1972.   clause->GetAttributeValue("fixed_width", iVal);
  1973.   m_fixedWidth = (iVal != 0);
  1974.  
  1975.   iVal = (int) m_fixedHeight;
  1976.   clause->GetAttributeValue("fixed_height", iVal);
  1977.   m_fixedHeight = (iVal != 0);
  1978.  
  1979.   clause->GetAttributeValue("format_mode", m_formatMode);
  1980.   clause->GetAttributeValue("shadow_mode", m_shadowMode);
  1981.  
  1982.   iVal = m_branchNeckLength;
  1983.   clause->GetAttributeValue("neck_length", iVal);
  1984.   m_branchNeckLength = iVal;
  1985.  
  1986.   iVal = m_branchStemLength;
  1987.   clause->GetAttributeValue("stem_length", iVal);
  1988.   m_branchStemLength = iVal;
  1989.  
  1990.   iVal = m_branchSpacing;
  1991.   clause->GetAttributeValue("branch_spacing", iVal);
  1992.   m_branchSpacing = iVal;
  1993.  
  1994.   clause->GetAttributeValue("branch_style", m_branchStyle);
  1995.  
  1996.   iVal = (int) m_centreResize;
  1997.   clause->GetAttributeValue("centre_resize", iVal);
  1998.   m_centreResize = (iVal != 0);
  1999.  
  2000.   iVal = (int) m_maintainAspectRatio;
  2001.   clause->GetAttributeValue("maintain_aspect_ratio", iVal);
  2002.   m_maintainAspectRatio = (iVal != 0);
  2003.  
  2004.   iVal = (int) m_highlighted;
  2005.   clause->GetAttributeValue("hilite", iVal);
  2006.   m_highlighted = (iVal != 0);
  2007.  
  2008.   clause->GetAttributeValue("rotation", m_rotation);
  2009.  
  2010.   if (pen_string == "")
  2011.     pen_string = "BLACK";
  2012.   if (brush_string == "")
  2013.     brush_string = "WHITE";
  2014.  
  2015.   if (pen_string.GetChar(0) == '#')
  2016.   {
  2017.     wxColour col(oglHexToColour(pen_string.After('#')));
  2018.     m_pen = wxThePenList->FindOrCreatePen(col, pen_width, pen_style);
  2019.   }
  2020.   else
  2021.     m_pen = wxThePenList->FindOrCreatePen(pen_string, pen_width, pen_style);
  2022.  
  2023.   if (!m_pen)
  2024.     m_pen = wxBLACK_PEN;
  2025.  
  2026.   if (brush_string.GetChar(0) == '#')
  2027.   {
  2028.     wxColour col(oglHexToColour(brush_string.After('#')));
  2029.     m_brush = wxTheBrushList->FindOrCreateBrush(col, brush_style);
  2030.   }
  2031.   else
  2032.     m_brush = wxTheBrushList->FindOrCreateBrush(brush_string, brush_style);
  2033.  
  2034.   if (!m_brush)
  2035.     m_brush = wxWHITE_BRUSH;
  2036.  
  2037.   int point_size = 10;
  2038.   clause->GetAttributeValue("point_size", point_size);
  2039.   SetFont(oglMatchFont(point_size));
  2040.  
  2041.   // Read user-defined attachment points, if any
  2042.   wxExpr *attachmentList = clause->AttributeValue("user_attachments");
  2043.   if (attachmentList)
  2044.   {
  2045.     wxExpr *pointExpr = attachmentList->GetFirst();
  2046.     while (pointExpr)
  2047.     {
  2048.       wxExpr *idExpr = pointExpr->Nth(0);
  2049.       wxExpr *xExpr = pointExpr->Nth(1);
  2050.       wxExpr *yExpr = pointExpr->Nth(2);
  2051.       if (idExpr && xExpr && yExpr)
  2052.       {
  2053.         wxAttachmentPoint *point = new wxAttachmentPoint;
  2054.         point->m_id = (int)idExpr->IntegerValue();
  2055.         point->m_x = xExpr->RealValue();
  2056.         point->m_y = yExpr->RealValue();
  2057.         m_attachmentPoints.Append((wxObject *)point);
  2058.       }
  2059.       pointExpr = pointExpr->GetNext();
  2060.     }
  2061.   }
  2062.  
  2063.   // Read text regions
  2064.   ReadRegions(clause);
  2065. }
  2066.  
  2067. void wxShape::ReadRegions(wxExpr *clause)
  2068. {
  2069.   ClearRegions();
  2070.  
  2071.   // region1 = (regionName regionText x y width height minWidth minHeight proportionX proportionY
  2072.   //            formatMode fontSize fontFamily fontStyle fontWeight textColour)
  2073.   int regionNo = 1;
  2074.   char regionNameBuf[20];
  2075.   char textNameBuf[20];
  2076.  
  2077.   wxExpr *regionExpr = NULL;
  2078.   wxExpr *textExpr = NULL;
  2079.   sprintf(regionNameBuf, "region%d", regionNo);
  2080.   sprintf(textNameBuf, "text%d", regionNo);
  2081.  
  2082.   m_formatted = TRUE;  // Assume text is formatted unless we prove otherwise
  2083.  
  2084.   while ((regionExpr = clause->AttributeValue(regionNameBuf)))
  2085.   {
  2086.     /*
  2087.      * Get the region information
  2088.      *
  2089.      */
  2090.  
  2091.     wxString regionName("");
  2092.     wxString regionText("");
  2093.     double x = 0.0;
  2094.     double y = 0.0;
  2095.     double width = 0.0;
  2096.     double height = 0.0;
  2097.     double minWidth = 5.0;
  2098.     double minHeight = 5.0;
  2099.     double m_regionProportionX = -1.0;
  2100.     double m_regionProportionY = -1.0;
  2101.     int formatMode = FORMAT_NONE;
  2102.     int fontSize = 10;
  2103.     int fontFamily = wxSWISS;
  2104.     int fontStyle = wxNORMAL;
  2105.     int fontWeight = wxNORMAL;
  2106.     wxString regionTextColour("");
  2107.     wxString penColour("");
  2108.     int penStyle = wxSOLID;
  2109.  
  2110.     if (regionExpr->Type() == wxExprList)
  2111.     {
  2112.       wxExpr *nameExpr = regionExpr->Nth(0);
  2113.       wxExpr *textExpr = regionExpr->Nth(1);
  2114.       wxExpr *xExpr = regionExpr->Nth(2);
  2115.       wxExpr *yExpr = regionExpr->Nth(3);
  2116.       wxExpr *widthExpr = regionExpr->Nth(4);
  2117.       wxExpr *heightExpr = regionExpr->Nth(5);
  2118.       wxExpr *minWidthExpr = regionExpr->Nth(6);
  2119.       wxExpr *minHeightExpr = regionExpr->Nth(7);
  2120.       wxExpr *propXExpr = regionExpr->Nth(8);
  2121.       wxExpr *propYExpr = regionExpr->Nth(9);
  2122.       wxExpr *formatExpr = regionExpr->Nth(10);
  2123.       wxExpr *sizeExpr = regionExpr->Nth(11);
  2124.       wxExpr *familyExpr = regionExpr->Nth(12);
  2125.       wxExpr *styleExpr = regionExpr->Nth(13);
  2126.       wxExpr *weightExpr = regionExpr->Nth(14);
  2127.       wxExpr *colourExpr = regionExpr->Nth(15);
  2128.       wxExpr *penColourExpr = regionExpr->Nth(16);
  2129.       wxExpr *penStyleExpr = regionExpr->Nth(17);
  2130.  
  2131.       regionName = nameExpr->StringValue();
  2132.       regionText = textExpr->StringValue();
  2133.  
  2134.       x = xExpr->RealValue();
  2135.       y = yExpr->RealValue();
  2136.  
  2137.       width = widthExpr->RealValue();
  2138.       height = heightExpr->RealValue();
  2139.  
  2140.       minWidth = minWidthExpr->RealValue();
  2141.       minHeight = minHeightExpr->RealValue();
  2142.  
  2143.       m_regionProportionX = propXExpr->RealValue();
  2144.       m_regionProportionY = propYExpr->RealValue();
  2145.  
  2146.       formatMode = (int) formatExpr->IntegerValue();
  2147.       fontSize = (int)sizeExpr->IntegerValue();
  2148.       fontFamily = (int)familyExpr->IntegerValue();
  2149.       fontStyle = (int)styleExpr->IntegerValue();
  2150.       fontWeight = (int)weightExpr->IntegerValue();
  2151.  
  2152.       if (colourExpr)
  2153.       {
  2154.         regionTextColour = colourExpr->StringValue();
  2155.       }
  2156.       else
  2157.         regionTextColour = "BLACK";
  2158.  
  2159.       if (penColourExpr)
  2160.         penColour = penColourExpr->StringValue();
  2161.       if (penStyleExpr)
  2162.         penStyle = (int)penStyleExpr->IntegerValue();
  2163.     }
  2164.     wxFont *font = wxTheFontList->FindOrCreateFont(fontSize, fontFamily, fontStyle, fontWeight);
  2165.  
  2166.     wxShapeRegion *region = new wxShapeRegion;
  2167.     region->SetProportions(m_regionProportionX, m_regionProportionY);
  2168.     region->SetFont(font);
  2169.     region->SetSize(width, height);
  2170.     region->SetPosition(x, y);
  2171.     region->SetMinSize(minWidth, minHeight);
  2172.     region->SetFormatMode(formatMode);
  2173.     region->SetPenStyle(penStyle);
  2174.     if (penColour != "")
  2175.       region->SetPenColour(penColour);
  2176.  
  2177.     region->m_textColour = regionTextColour;
  2178.     region->m_regionText = regionText;
  2179.     region->m_regionName = regionName;
  2180.  
  2181.     m_regions.Append(region);
  2182.  
  2183.     /*
  2184.      * Get the formatted text strings
  2185.      *
  2186.      */
  2187.     textExpr = clause->AttributeValue(textNameBuf);
  2188.     if (textExpr && (textExpr->Type() == wxExprList))
  2189.     {
  2190.       wxExpr *node = textExpr->value.first;
  2191.       while (node)
  2192.       {
  2193.         wxExpr *string_expr = node;
  2194.         double the_x = 0.0;
  2195.         double the_y = 0.0;
  2196.         wxString the_string("");
  2197.  
  2198.         // string_expr can either be a string, or a list of
  2199.         // 3 elements: x, y, and string.
  2200.         if (string_expr->Type() == wxExprString)
  2201.         {
  2202.           the_string = string_expr->StringValue();
  2203.           m_formatted = FALSE;
  2204.         }
  2205.         else if (string_expr->Type() == wxExprList)
  2206.         {
  2207.           wxExpr *first = string_expr->value.first;
  2208.           wxExpr *second = first ? first->next : (wxExpr*) NULL;
  2209.           wxExpr *third = second ? second->next : (wxExpr*) NULL;
  2210.  
  2211.           if (first && second && third &&
  2212.               (first->Type() == wxExprReal || first->Type() == wxExprInteger) &&
  2213.               (second->Type() == wxExprReal || second->Type() == wxExprInteger) &&
  2214.               third->Type() == wxExprString)
  2215.           {
  2216.             if (first->Type() == wxExprReal)
  2217.               the_x = first->RealValue();
  2218.             else the_x = (double)first->IntegerValue();
  2219.  
  2220.             if (second->Type() == wxExprReal)
  2221.               the_y = second->RealValue();
  2222.             else the_y = (double)second->IntegerValue();
  2223.  
  2224.             the_string = third->StringValue();
  2225.           }
  2226.         }
  2227.         if (the_string)
  2228.         {
  2229.           wxShapeTextLine *line =
  2230.               new wxShapeTextLine(the_x, the_y, the_string);
  2231.           region->m_formattedText.Append(line);
  2232.         }
  2233.         node = node->next;
  2234.       }
  2235.     }
  2236.  
  2237.     regionNo ++;
  2238.     sprintf(regionNameBuf, "region%d", regionNo);
  2239.     sprintf(textNameBuf, "text%d", regionNo);
  2240.   }
  2241.  
  2242.   // Compatibility: check for no regions (old file).
  2243.   // Lines and divided rectangles must deal with this compatibility
  2244.   // theirselves. Composites _may_ not have any regions anyway.
  2245.   if ((m_regions.Number() == 0) &&
  2246.       !this->IsKindOf(CLASSINFO(wxLineShape)) && !this->IsKindOf(CLASSINFO(wxDividedShape)) &&
  2247.       !this->IsKindOf(CLASSINFO(wxCompositeShape)))
  2248.   {
  2249.     wxShapeRegion *newRegion = new wxShapeRegion;
  2250.     newRegion->SetName("0");
  2251.     m_regions.Append((wxObject *)newRegion);
  2252.     if (m_text.Number() > 0)
  2253.     {
  2254.       newRegion->ClearText();
  2255.       wxNode *node = m_text.First();
  2256.       while (node)
  2257.       {
  2258.         wxShapeTextLine *textLine = (wxShapeTextLine *)node->Data();
  2259.         wxNode *next = node->Next();
  2260.         newRegion->GetFormattedText().Append((wxObject *)textLine);
  2261.         delete node;
  2262.         node = next;
  2263.       }
  2264.     }
  2265.   }
  2266. }
  2267.  
  2268. #endif
  2269.  
  2270. void wxShape::Copy(wxShape& copy)
  2271. {
  2272.   copy.m_id = m_id;
  2273.   copy.m_xpos = m_xpos;
  2274.   copy.m_ypos = m_ypos;
  2275.   copy.m_pen = m_pen;
  2276.   copy.m_brush = m_brush;
  2277.   copy.m_textColour = m_textColour;
  2278.   copy.m_centreResize = m_centreResize;
  2279.   copy.m_maintainAspectRatio = m_maintainAspectRatio;
  2280.   copy.m_attachmentMode = m_attachmentMode;
  2281.   copy.m_spaceAttachments = m_spaceAttachments;
  2282.   copy.m_highlighted = m_highlighted;
  2283.   copy.m_rotation = m_rotation;
  2284.   copy.m_textColourName = m_textColourName;
  2285.   copy.m_regionName = m_regionName;
  2286.  
  2287.   copy.m_sensitivity = m_sensitivity;
  2288.   copy.m_draggable = m_draggable;
  2289.   copy.m_fixedWidth = m_fixedWidth;
  2290.   copy.m_fixedHeight = m_fixedHeight;
  2291.   copy.m_formatMode = m_formatMode;
  2292.   copy.m_drawHandles = m_drawHandles;
  2293.  
  2294.   copy.m_visible = m_visible;
  2295.   copy.m_shadowMode = m_shadowMode;
  2296.   copy.m_shadowOffsetX = m_shadowOffsetX;
  2297.   copy.m_shadowOffsetY = m_shadowOffsetY;
  2298.   copy.m_shadowBrush = m_shadowBrush;
  2299.  
  2300.   copy.m_branchNeckLength = m_branchNeckLength;
  2301.   copy.m_branchStemLength = m_branchStemLength;
  2302.   copy.m_branchSpacing = m_branchSpacing;
  2303.  
  2304.   // Copy text regions
  2305.   copy.ClearRegions();
  2306.   wxNode *node = m_regions.First();
  2307.   while (node)
  2308.   {
  2309.     wxShapeRegion *region = (wxShapeRegion *)node->Data();
  2310.     wxShapeRegion *newRegion = new wxShapeRegion(*region);
  2311.     copy.m_regions.Append(newRegion);
  2312.     node = node->Next();
  2313.   }
  2314.  
  2315.   // Copy attachments
  2316.   copy.ClearAttachments();
  2317.   node = m_attachmentPoints.First();
  2318.   while (node)
  2319.   {
  2320.     wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
  2321.     wxAttachmentPoint *newPoint = new wxAttachmentPoint;
  2322.     newPoint->m_id = point->m_id;
  2323.     newPoint->m_x = point->m_x;
  2324.     newPoint->m_y = point->m_y;
  2325.     copy.m_attachmentPoints.Append((wxObject *)newPoint);
  2326.     node = node->Next();
  2327.   }
  2328.  
  2329.   // Copy lines
  2330.   copy.m_lines.Clear();
  2331.   node = m_lines.First();
  2332.   while (node)
  2333.   {
  2334.     wxLineShape* line = (wxLineShape*) node->Data();
  2335.     copy.m_lines.Append(line);
  2336.     node = node->Next();
  2337.   }
  2338. }
  2339.  
  2340. // Create and return a new, fully copied object.
  2341. wxShape *wxShape::CreateNewCopy(bool resetMapping, bool recompute)
  2342. {
  2343.   if (resetMapping)
  2344.     oglObjectCopyMapping.Clear();
  2345.  
  2346.   wxShape* newObject = (wxShape*) GetClassInfo()->CreateObject();
  2347.  
  2348.   wxASSERT( (newObject != NULL) );
  2349.   wxASSERT( (newObject->IsKindOf(CLASSINFO(wxShape))) );
  2350.  
  2351.   Copy(*newObject);
  2352.  
  2353.   if (GetEventHandler() != this)
  2354.   {
  2355.     wxShapeEvtHandler* newHandler = GetEventHandler()->CreateNewCopy();
  2356.     newObject->SetEventHandler(newHandler);
  2357.     newObject->SetPreviousHandler(NULL);
  2358.     newHandler->SetPreviousHandler(newObject);
  2359.     newHandler->SetShape(newObject);
  2360.   }
  2361.  
  2362.   if (recompute)
  2363.     newObject->Recompute();
  2364.   return newObject;
  2365. }
  2366.  
  2367. // Does the copying for this object, including copying event
  2368. // handler data if any. Calls the virtual Copy function.
  2369. void wxShape::CopyWithHandler(wxShape& copy)
  2370. {
  2371.     Copy(copy);
  2372.  
  2373.     if (GetEventHandler() != this)
  2374.     {
  2375.         wxASSERT( copy.GetEventHandler() != NULL );
  2376.         wxASSERT( copy.GetEventHandler() != (©) );
  2377.         wxASSERT( GetEventHandler()->GetClassInfo() == copy.GetEventHandler()->GetClassInfo() );
  2378.         GetEventHandler()->CopyData(* (copy.GetEventHandler()));
  2379.     }
  2380. }
  2381.  
  2382.  
  2383. // Default - make 6 control points
  2384. void wxShape::MakeControlPoints()
  2385. {
  2386.   double maxX, maxY, minX, minY;
  2387.  
  2388.   GetBoundingBoxMax(&maxX, &maxY);
  2389.   GetBoundingBoxMin(&minX, &minY);
  2390.  
  2391.   double widthMin = (double)(minX + CONTROL_POINT_SIZE + 2);
  2392.   double heightMin = (double)(minY + CONTROL_POINT_SIZE + 2);
  2393.  
  2394.   // Offsets from main object
  2395.   double top = (double)(- (heightMin / 2.0));
  2396.   double bottom = (double)(heightMin / 2.0 + (maxY - minY));
  2397.   double left = (double)(- (widthMin / 2.0));
  2398.   double right = (double)(widthMin / 2.0 + (maxX - minX));
  2399.  
  2400.   wxControlPoint *control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, top,
  2401.                                            CONTROL_POINT_DIAGONAL);
  2402.   m_canvas->AddShape(control);
  2403.   m_controlPoints.Append(control);
  2404.  
  2405.   control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, 0, top,
  2406.                                            CONTROL_POINT_VERTICAL);
  2407.   m_canvas->AddShape(control);
  2408.   m_controlPoints.Append(control);
  2409.  
  2410.   control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, top,
  2411.                                            CONTROL_POINT_DIAGONAL);
  2412.   m_canvas->AddShape(control);
  2413.   m_controlPoints.Append(control);
  2414.  
  2415.   control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, 0,
  2416.                                            CONTROL_POINT_HORIZONTAL);
  2417.   m_canvas->AddShape(control);
  2418.   m_controlPoints.Append(control);
  2419.  
  2420.   control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, bottom,
  2421.                                            CONTROL_POINT_DIAGONAL);
  2422.   m_canvas->AddShape(control);
  2423.   m_controlPoints.Append(control);
  2424.  
  2425.   control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, 0, bottom,
  2426.                                            CONTROL_POINT_VERTICAL);
  2427.   m_canvas->AddShape(control);
  2428.   m_controlPoints.Append(control);
  2429.  
  2430.   control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, bottom,
  2431.                                            CONTROL_POINT_DIAGONAL);
  2432.   m_canvas->AddShape(control);
  2433.   m_controlPoints.Append(control);
  2434.  
  2435.   control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, 0,
  2436.                                            CONTROL_POINT_HORIZONTAL);
  2437.   m_canvas->AddShape(control);
  2438.   m_controlPoints.Append(control);
  2439.  
  2440. }
  2441.  
  2442. void wxShape::MakeMandatoryControlPoints()
  2443. {
  2444.   wxNode *node = m_children.First();
  2445.   while (node)
  2446.   {
  2447.     wxShape *child = (wxShape *)node->Data();
  2448.     child->MakeMandatoryControlPoints();
  2449.     node = node->Next();
  2450.   }
  2451. }
  2452.  
  2453. void wxShape::ResetMandatoryControlPoints()
  2454. {
  2455.   wxNode *node = m_children.First();
  2456.   while (node)
  2457.   {
  2458.     wxShape *child = (wxShape *)node->Data();
  2459.     child->ResetMandatoryControlPoints();
  2460.     node = node->Next();
  2461.   }
  2462. }
  2463.  
  2464. void wxShape::ResetControlPoints()
  2465. {
  2466.   ResetMandatoryControlPoints();
  2467.  
  2468.   if (m_controlPoints.Number() < 1)
  2469.     return;
  2470.  
  2471.   double maxX, maxY, minX, minY;
  2472.  
  2473.   GetBoundingBoxMax(&maxX, &maxY);
  2474.   GetBoundingBoxMin(&minX, &minY);
  2475.  
  2476.   double widthMin = (double)(minX + CONTROL_POINT_SIZE + 2);
  2477.   double heightMin = (double)(minY + CONTROL_POINT_SIZE + 2);
  2478.  
  2479.   // Offsets from main object
  2480.   double top = (double)(- (heightMin / 2.0));
  2481.   double bottom = (double)(heightMin / 2.0 + (maxY - minY));
  2482.   double left = (double)(- (widthMin / 2.0));
  2483.   double right = (double)(widthMin / 2.0 + (maxX - minX));
  2484.  
  2485.   wxNode *node = m_controlPoints.First();
  2486.   wxControlPoint *control = (wxControlPoint *)node->Data();
  2487.   control->m_xoffset = left; control->m_yoffset = top;
  2488.  
  2489.   node = node->Next(); control = (wxControlPoint *)node->Data();
  2490.   control->m_xoffset = 0; control->m_yoffset = top;
  2491.  
  2492.   node = node->Next(); control = (wxControlPoint *)node->Data();
  2493.   control->m_xoffset = right; control->m_yoffset = top;
  2494.  
  2495.   node = node->Next(); control = (wxControlPoint *)node->Data();
  2496.   control->m_xoffset = right; control->m_yoffset = 0;
  2497.  
  2498.   node = node->Next(); control = (wxControlPoint *)node->Data();
  2499.   control->m_xoffset = right; control->m_yoffset = bottom;
  2500.  
  2501.   node = node->Next(); control = (wxControlPoint *)node->Data();
  2502.   control->m_xoffset = 0; control->m_yoffset = bottom;
  2503.  
  2504.   node = node->Next(); control = (wxControlPoint *)node->Data();
  2505.   control->m_xoffset = left; control->m_yoffset = bottom;
  2506.  
  2507.   node = node->Next(); control = (wxControlPoint *)node->Data();
  2508.   control->m_xoffset = left; control->m_yoffset = 0;
  2509. }
  2510.  
  2511. void wxShape::DeleteControlPoints(wxDC *dc)
  2512. {
  2513.   wxNode *node = m_controlPoints.First();
  2514.   while (node)
  2515.   {
  2516.     wxControlPoint *control = (wxControlPoint *)node->Data();
  2517.     if (dc)
  2518.         control->GetEventHandler()->OnErase(*dc);
  2519.     m_canvas->RemoveShape(control);
  2520.     delete control;
  2521.     delete node;
  2522.     node = m_controlPoints.First();
  2523.   }
  2524.   // Children of divisions are contained objects,
  2525.   // so stop here
  2526.   if (!IsKindOf(CLASSINFO(wxDivisionShape)))
  2527.   {
  2528.     node = m_children.First();
  2529.     while (node)
  2530.     {
  2531.       wxShape *child = (wxShape *)node->Data();
  2532.       child->DeleteControlPoints(dc);
  2533.       node = node->Next();
  2534.     }
  2535.   }
  2536. }
  2537.  
  2538. void wxShape::OnDrawControlPoints(wxDC& dc)
  2539. {
  2540.   if (!m_drawHandles)
  2541.     return;
  2542.  
  2543.   dc.SetBrush(* wxBLACK_BRUSH);
  2544.   dc.SetPen(* wxBLACK_PEN);
  2545.  
  2546.   wxNode *node = m_controlPoints.First();
  2547.   while (node)
  2548.   {
  2549.     wxControlPoint *control = (wxControlPoint *)node->Data();
  2550.     control->Draw(dc);
  2551.     node = node->Next();
  2552.   }
  2553.   // Children of divisions are contained objects,
  2554.   // so stop here.
  2555.   // This test bypasses the type facility for speed
  2556.   // (critical when drawing)
  2557.   if (!IsKindOf(CLASSINFO(wxDivisionShape)))
  2558.   {
  2559.     node = m_children.First();
  2560.     while (node)
  2561.     {
  2562.       wxShape *child = (wxShape *)node->Data();
  2563.       child->GetEventHandler()->OnDrawControlPoints(dc);
  2564.       node = node->Next();
  2565.     }
  2566.   }
  2567. }
  2568.  
  2569. void wxShape::OnEraseControlPoints(wxDC& dc)
  2570. {
  2571.   wxNode *node = m_controlPoints.First();
  2572.   while (node)
  2573.   {
  2574.     wxControlPoint *control = (wxControlPoint *)node->Data();
  2575.     control->Erase(dc);
  2576.     node = node->Next();
  2577.   }
  2578.   if (!IsKindOf(CLASSINFO(wxDivisionShape)))
  2579.   {
  2580.     node = m_children.First();
  2581.     while (node)
  2582.     {
  2583.       wxShape *child = (wxShape *)node->Data();
  2584.       child->GetEventHandler()->OnEraseControlPoints(dc);
  2585.       node = node->Next();
  2586.     }
  2587.   }
  2588. }
  2589.  
  2590. void wxShape::Select(bool select, wxDC* dc)
  2591. {
  2592.   m_selected = select;
  2593.   if (select)
  2594.   {
  2595.     MakeControlPoints();
  2596.     // Children of divisions are contained objects,
  2597.     // so stop here
  2598.     if (!IsKindOf(CLASSINFO(wxDivisionShape)))
  2599.     {
  2600.       wxNode *node = m_children.First();
  2601.       while (node)
  2602.       {
  2603.         wxShape *child = (wxShape *)node->Data();
  2604.         child->MakeMandatoryControlPoints();
  2605.         node = node->Next();
  2606.       }
  2607.     }
  2608.     if (dc)
  2609.         GetEventHandler()->OnDrawControlPoints(*dc);
  2610.   }
  2611.   if (!select)
  2612.   {
  2613.     DeleteControlPoints(dc);
  2614.     if (!IsKindOf(CLASSINFO(wxDivisionShape)))
  2615.     {
  2616.       wxNode *node = m_children.First();
  2617.       while (node)
  2618.       {
  2619.         wxShape *child = (wxShape *)node->Data();
  2620.         child->DeleteControlPoints(dc);
  2621.         node = node->Next();
  2622.       }
  2623.     }
  2624.   }
  2625. }
  2626.  
  2627. bool wxShape::Selected() const
  2628. {
  2629.   return m_selected;
  2630. }
  2631.  
  2632. bool wxShape::AncestorSelected() const
  2633. {
  2634.   if (m_selected) return TRUE;
  2635.   if (!GetParent())
  2636.     return FALSE;
  2637.   else
  2638.     return GetParent()->AncestorSelected();
  2639. }
  2640.  
  2641. int wxShape::GetNumberOfAttachments() const
  2642. {
  2643.   // Should return the MAXIMUM attachment point id here,
  2644.   // so higher-level functions can iterate through all attachments,
  2645.   // even if they're not contiguous.
  2646.   if (m_attachmentPoints.Number() == 0)
  2647.     return 4;
  2648.   else
  2649.   {
  2650.     int maxN = 3;
  2651.     wxNode *node = m_attachmentPoints.First();
  2652.     while (node)
  2653.     {
  2654.       wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
  2655.       if (point->m_id > maxN)
  2656.         maxN = point->m_id;
  2657.       node = node->Next();
  2658.     }
  2659.     return maxN+1;;
  2660.   }
  2661. }
  2662.  
  2663. bool wxShape::AttachmentIsValid(int attachment) const
  2664. {
  2665.   if (m_attachmentPoints.Number() == 0)
  2666.   {
  2667.     return ((attachment >= 0) && (attachment < 4)) ;
  2668.   }
  2669.  
  2670.   wxNode *node = m_attachmentPoints.First();
  2671.   while (node)
  2672.   {
  2673.     wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
  2674.     if (point->m_id == attachment)
  2675.       return TRUE;
  2676.     node = node->Next();
  2677.   }
  2678.   return FALSE;
  2679. }
  2680.  
  2681. bool wxShape::GetAttachmentPosition(int attachment, double *x, double *y,
  2682.                                          int nth, int no_arcs, wxLineShape *line)
  2683. {
  2684.     if (m_attachmentMode == ATTACHMENT_MODE_NONE)
  2685.     {
  2686.         *x = m_xpos; *y = m_ypos;
  2687.         return TRUE;
  2688.     }
  2689.     else if (m_attachmentMode == ATTACHMENT_MODE_BRANCHING)
  2690.     {
  2691.         wxRealPoint pt, stemPt;
  2692.         GetBranchingAttachmentPoint(attachment, nth, pt, stemPt);
  2693.         *x = pt.x;
  2694.         *y = pt.y;
  2695.         return TRUE;
  2696.     }
  2697.     else if (m_attachmentMode == ATTACHMENT_MODE_EDGE)
  2698.     {
  2699.         if (m_attachmentPoints.Number() > 0)
  2700.         {
  2701.             wxNode *node = m_attachmentPoints.First();
  2702.             while (node)
  2703.             {
  2704.                 wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
  2705.                 if (point->m_id == attachment)
  2706.                 {
  2707.                     *x = (double)(m_xpos + point->m_x);
  2708.                     *y = (double)(m_ypos + point->m_y);
  2709.                     return TRUE;
  2710.                 }
  2711.                 node = node->Next();
  2712.             }
  2713.             *x = m_xpos; *y = m_ypos;
  2714.             return FALSE;
  2715.         }
  2716.         else
  2717.         {
  2718.             // Assume is rectangular
  2719.             double w, h;
  2720.             GetBoundingBoxMax(&w, &h);
  2721.             double top = (double)(m_ypos + h/2.0);
  2722.             double bottom = (double)(m_ypos - h/2.0);
  2723.             double left = (double)(m_xpos - w/2.0);
  2724.             double right = (double)(m_xpos + w/2.0);
  2725.  
  2726.             bool isEnd = (line && line->IsEnd(this));
  2727.  
  2728.             int physicalAttachment = LogicalToPhysicalAttachment(attachment);
  2729.  
  2730.             // Simplified code
  2731.             switch (physicalAttachment)
  2732.             {
  2733.                 case 0:
  2734.                 {
  2735.                     wxRealPoint pt = CalcSimpleAttachment(wxRealPoint(left, bottom), wxRealPoint(right, bottom),
  2736.                             nth, no_arcs, line);
  2737.  
  2738.                     *x = pt.x; *y = pt.y;
  2739.                     break;
  2740.                 }
  2741.                 case 1:
  2742.                 {
  2743.                     wxRealPoint pt = CalcSimpleAttachment(wxRealPoint(right, bottom), wxRealPoint(right, top),
  2744.                             nth, no_arcs, line);
  2745.  
  2746.                     *x = pt.x; *y = pt.y;
  2747.                     break;
  2748.                 }
  2749.                 case 2:
  2750.                 {
  2751.                     wxRealPoint pt = CalcSimpleAttachment(wxRealPoint(left, top), wxRealPoint(right, top),
  2752.                             nth, no_arcs, line);
  2753.  
  2754.                     *x = pt.x; *y = pt.y;
  2755.                     break;
  2756.                 }
  2757.                 case 3:
  2758.                 {
  2759.                     wxRealPoint pt = CalcSimpleAttachment(wxRealPoint(left, bottom), wxRealPoint(left, top),
  2760.                             nth, no_arcs, line);
  2761.  
  2762.                     *x = pt.x; *y = pt.y;
  2763.                     break;
  2764.                 }
  2765.                 default:
  2766.                 {
  2767.                     return FALSE;
  2768.                     break;
  2769.                 }
  2770.             }
  2771.             return TRUE;
  2772.         }
  2773.     }
  2774.     return FALSE;
  2775. }
  2776.  
  2777. void wxShape::GetBoundingBoxMax(double *w, double *h)
  2778. {
  2779.   double ww, hh;
  2780.   GetBoundingBoxMin(&ww, &hh);
  2781.   if (m_shadowMode != SHADOW_NONE)
  2782.   {
  2783.     ww += m_shadowOffsetX;
  2784.     hh += m_shadowOffsetY;
  2785.   }
  2786.   *w = ww;
  2787.   *h = hh;
  2788. }
  2789.  
  2790. // Returns TRUE if image is a descendant of this composite
  2791. bool wxShape::HasDescendant(wxShape *image)
  2792. {
  2793.   if (image == this)
  2794.     return TRUE;
  2795.   wxNode *node = m_children.First();
  2796.   while (node)
  2797.   {
  2798.     wxShape *child = (wxShape *)node->Data();
  2799.     bool ans = child->HasDescendant(image);
  2800.     if (ans)
  2801.       return TRUE;
  2802.     node = node->Next();
  2803.   }
  2804.   return FALSE;
  2805. }
  2806.  
  2807. // Clears points from a list of wxRealPoints, and clears list
  2808. void wxShape::ClearPointList(wxList& list)
  2809. {
  2810.     wxNode* node = list.First();
  2811.     while (node)
  2812.     {
  2813.         wxRealPoint* pt = (wxRealPoint*) node->Data();
  2814.         delete pt;
  2815.  
  2816.         node = node->Next();
  2817.     }
  2818.     list.Clear();
  2819. }
  2820.  
  2821. // Assuming the attachment lies along a vertical or horizontal line,
  2822. // calculate the position on that point.
  2823. wxRealPoint wxShape::CalcSimpleAttachment(const wxRealPoint& pt1, const wxRealPoint& pt2,
  2824.     int nth, int noArcs, wxLineShape* line)
  2825. {
  2826.     bool isEnd = (line && line->IsEnd(this));
  2827.  
  2828.     // Are we horizontal or vertical?
  2829.     bool isHorizontal = (oglRoughlyEqual(pt1.y, pt2.y) == TRUE);
  2830.  
  2831.     double x, y;
  2832.  
  2833.     if (isHorizontal)
  2834.     {
  2835.         wxRealPoint firstPoint, secondPoint;
  2836.         if (pt1.x > pt2.x)
  2837.         {
  2838.             firstPoint = pt2;
  2839.             secondPoint = pt1;
  2840.         }
  2841.         else
  2842.         {
  2843.             firstPoint = pt1;
  2844.             secondPoint = pt2;
  2845.         }
  2846.  
  2847.         if (m_spaceAttachments)
  2848.         {
  2849.           if (line && (line->GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE))
  2850.           {
  2851.             // Align line according to the next handle along
  2852.             wxRealPoint *point = line->GetNextControlPoint(this);
  2853.             if (point->x < firstPoint.x)
  2854.               x = firstPoint.x;
  2855.             else if (point->x > secondPoint.x)
  2856.               x = secondPoint.x;
  2857.             else
  2858.               x = point->x;
  2859.           }
  2860.           else
  2861.             x = firstPoint.x + (nth + 1)*(secondPoint.x - firstPoint.x)/(noArcs + 1);
  2862.         }
  2863.         else x = (secondPoint.x - firstPoint.x)/2.0; // Midpoint
  2864.  
  2865.         y = pt1.y;
  2866.     }
  2867.     else
  2868.     {
  2869.         wxASSERT( oglRoughlyEqual(pt1.x, pt2.x) == TRUE );
  2870.  
  2871.         wxRealPoint firstPoint, secondPoint;
  2872.         if (pt1.y > pt2.y)
  2873.         {
  2874.             firstPoint = pt2;
  2875.             secondPoint = pt1;
  2876.         }
  2877.         else
  2878.         {
  2879.             firstPoint = pt1;
  2880.             secondPoint = pt2;
  2881.         }
  2882.  
  2883.         if (m_spaceAttachments)
  2884.         {
  2885.           if (line && (line->GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE))
  2886.           {
  2887.             // Align line according to the next handle along
  2888.             wxRealPoint *point = line->GetNextControlPoint(this);
  2889.             if (point->y < firstPoint.y)
  2890.               y = firstPoint.y;
  2891.             else if (point->y > secondPoint.y)
  2892.               y = secondPoint.y;
  2893.             else
  2894.               y = point->y;
  2895.           }
  2896.           else
  2897.             y = firstPoint.y + (nth + 1)*(secondPoint.y - firstPoint.y)/(noArcs + 1);
  2898.         }
  2899.         else y = (secondPoint.y - firstPoint.y)/2.0; // Midpoint
  2900.  
  2901.         x = pt1.x;
  2902.     }
  2903.  
  2904.     return wxRealPoint(x, y);
  2905. }
  2906.  
  2907. // Return the zero-based position in m_lines of line.
  2908. int wxShape::GetLinePosition(wxLineShape* line)
  2909. {
  2910.     int i = 0;
  2911.     for (i = 0; i < m_lines.Number(); i++)
  2912.         if ((wxLineShape*) (m_lines.Nth(i)->Data()) == line)
  2913.             return i;
  2914.  
  2915.     return 0;
  2916. }
  2917.  
  2918. //
  2919. //             |________|
  2920. //                 | <- root
  2921. //                 | <- neck
  2922. // shoulder1 ->---------<- shoulder2
  2923. //             | | | | |
  2924. //                      <- branching attachment point N-1
  2925.  
  2926. // This function gets information about where branching connections go.
  2927. // Returns FALSE if there are no lines at this attachment.
  2928. bool wxShape::GetBranchingAttachmentInfo(int attachment, wxRealPoint& root, wxRealPoint& neck,
  2929.     wxRealPoint& shoulder1, wxRealPoint& shoulder2)
  2930. {
  2931.     int physicalAttachment = LogicalToPhysicalAttachment(attachment);
  2932.  
  2933.     // Number of lines at this attachment.
  2934.     int lineCount = GetAttachmentLineCount(attachment);
  2935.  
  2936.     if (lineCount == 0)
  2937.         return FALSE;
  2938.  
  2939.     int totalBranchLength = m_branchSpacing * (lineCount - 1);
  2940.  
  2941.     root = GetBranchingAttachmentRoot(attachment);
  2942.  
  2943.     // Assume that we have attachment points 0 to 3: top, right, bottom, left.
  2944.     switch (physicalAttachment)
  2945.     {
  2946.         case 0:
  2947.         {
  2948.             neck.x = GetX();
  2949.             neck.y = root.y - m_branchNeckLength;
  2950.  
  2951.             shoulder1.x = root.x - (totalBranchLength/2.0) ;
  2952.             shoulder2.x = root.x + (totalBranchLength/2.0) ;
  2953.  
  2954.             shoulder1.y = neck.y;
  2955.             shoulder2.y = neck.y;
  2956.             break;
  2957.         }
  2958.         case 1:
  2959.         {
  2960.             neck.x = root.x + m_branchNeckLength;
  2961.             neck.y = root.y;
  2962.  
  2963.             shoulder1.x = neck.x ;
  2964.             shoulder2.x = neck.x ;
  2965.  
  2966.             shoulder1.y = neck.y - (totalBranchLength/2.0) ;
  2967.             shoulder2.y = neck.y + (totalBranchLength/2.0) ;
  2968.             break;
  2969.         }
  2970.         case 2:
  2971.         {
  2972.             neck.x = GetX();
  2973.             neck.y = root.y + m_branchNeckLength;
  2974.  
  2975.             shoulder1.x = root.x - (totalBranchLength/2.0) ;
  2976.             shoulder2.x = root.x + (totalBranchLength/2.0) ;
  2977.  
  2978.             shoulder1.y = neck.y;
  2979.             shoulder2.y = neck.y;
  2980.             break;
  2981.         }
  2982.         case 3:
  2983.         {
  2984.             neck.x = root.x - m_branchNeckLength;
  2985.             neck.y = root.y ;
  2986.  
  2987.             shoulder1.x = neck.x ;
  2988.             shoulder2.x = neck.x ;
  2989.  
  2990.             shoulder1.y = neck.y - (totalBranchLength/2.0) ;
  2991.             shoulder2.y = neck.y + (totalBranchLength/2.0) ;
  2992.             break;
  2993.         }
  2994.         default:
  2995.         {
  2996.             wxFAIL_MSG( wxT("Unrecognised attachment point in GetBranchingAttachmentInfo.") );
  2997.             break;
  2998.         }
  2999.     }
  3000.     return TRUE;
  3001. }
  3002.  
  3003. // n is the number of the adjoining line, from 0 to N-1 where N is the number of lines
  3004. // at this attachment point.
  3005. // Get the attachment point where the arc joins the stem, and also the point where the
  3006. // the stem meets the shoulder.
  3007. bool wxShape::GetBranchingAttachmentPoint(int attachment, int n, wxRealPoint& pt, wxRealPoint& stemPt)
  3008. {
  3009.     int physicalAttachment = LogicalToPhysicalAttachment(attachment);
  3010.  
  3011.     wxRealPoint root, neck, shoulder1, shoulder2;
  3012.     GetBranchingAttachmentInfo(attachment, root, neck, shoulder1, shoulder2);
  3013.  
  3014.     // Assume that we have attachment points 0 to 3: top, right, bottom, left.
  3015.     switch (physicalAttachment)
  3016.     {
  3017.         case 0:
  3018.         {
  3019.             pt.y = neck.y - m_branchStemLength;
  3020.             pt.x = shoulder1.x + n*m_branchSpacing;
  3021.  
  3022.             stemPt.x = pt.x;
  3023.             stemPt.y = neck.y;
  3024.             break;
  3025.         }
  3026.         case 2:
  3027.         {
  3028.             pt.y = neck.y + m_branchStemLength;
  3029.             pt.x = shoulder1.x + n*m_branchSpacing;
  3030.  
  3031.             stemPt.x = pt.x;
  3032.             stemPt.y = neck.y;
  3033.             break;
  3034.         }
  3035.         case 1:
  3036.         {
  3037.             pt.x = neck.x + m_branchStemLength;
  3038.             pt.y = shoulder1.y + n*m_branchSpacing;
  3039.  
  3040.             stemPt.x = neck.x;
  3041.             stemPt.y = pt.y;
  3042.             break;
  3043.         }
  3044.         case 3:
  3045.         {
  3046.             pt.x = neck.x - m_branchStemLength;
  3047.             pt.y = shoulder1.y + n*m_branchSpacing;
  3048.  
  3049.             stemPt.x = neck.x;
  3050.             stemPt.y = pt.y;
  3051.             break;
  3052.         }
  3053.         default:
  3054.         {
  3055.             wxFAIL_MSG( wxT("Unrecognised attachment point in GetBranchingAttachmentPoint.") );
  3056.             break;
  3057.         }
  3058.     }
  3059.  
  3060.     return TRUE;
  3061. }
  3062.  
  3063. // Get the number of lines at this attachment position.
  3064. int wxShape::GetAttachmentLineCount(int attachment) const
  3065. {
  3066.     int count = 0;
  3067.     wxNode* node = m_lines.First();
  3068.     while (node)
  3069.     {
  3070.         wxLineShape* lineShape = (wxLineShape*) node->Data();
  3071.         if ((lineShape->GetFrom() == this) && (lineShape->GetAttachmentFrom() == attachment))
  3072.             count ++;
  3073.         else if ((lineShape->GetTo() == this) && (lineShape->GetAttachmentTo() == attachment))
  3074.             count ++;
  3075.  
  3076.         node = node->Next();
  3077.     }
  3078.     return count;
  3079. }
  3080.  
  3081. // This function gets the root point at the given attachment.
  3082. wxRealPoint wxShape::GetBranchingAttachmentRoot(int attachment)
  3083. {
  3084.     int physicalAttachment = LogicalToPhysicalAttachment(attachment);
  3085.  
  3086.     wxRealPoint root;
  3087.  
  3088.     double width, height;
  3089.     GetBoundingBoxMax(& width, & height);
  3090.  
  3091.     // Assume that we have attachment points 0 to 3: top, right, bottom, left.
  3092.     switch (physicalAttachment)
  3093.     {
  3094.         case 0:
  3095.         {
  3096.             root.x = GetX() ;
  3097.             root.y = GetY() - height/2.0;
  3098.             break;
  3099.         }
  3100.         case 1:
  3101.         {
  3102.             root.x = GetX() + width/2.0;
  3103.             root.y = GetY() ;
  3104.             break;
  3105.         }
  3106.         case 2:
  3107.         {
  3108.             root.x = GetX() ;
  3109.             root.y = GetY() + height/2.0;
  3110.             break;
  3111.         }
  3112.         case 3:
  3113.         {
  3114.             root.x = GetX() - width/2.0;
  3115.             root.y = GetY() ;
  3116.             break;
  3117.         }
  3118.         default:
  3119.         {
  3120.             wxFAIL_MSG( wxT("Unrecognised attachment point in GetBranchingAttachmentRoot.") );
  3121.             break;
  3122.         }
  3123.     }
  3124.     return root;
  3125. }
  3126.  
  3127. // Draw or erase the branches (not the actual arcs though)
  3128. void wxShape::OnDrawBranches(wxDC& dc, int attachment, bool erase)
  3129. {
  3130.     int count = GetAttachmentLineCount(attachment);
  3131.     if (count == 0)
  3132.         return;
  3133.  
  3134.     wxRealPoint root, neck, shoulder1, shoulder2;
  3135.     GetBranchingAttachmentInfo(attachment, root, neck, shoulder1, shoulder2);
  3136.  
  3137.     if (erase)
  3138.     {
  3139.         dc.SetPen(*wxWHITE_PEN);
  3140.         dc.SetBrush(*wxWHITE_BRUSH);
  3141.     }
  3142.     else
  3143.     {
  3144.         dc.SetPen(*wxBLACK_PEN);
  3145.         dc.SetBrush(*wxBLACK_BRUSH);
  3146.     }
  3147.  
  3148.     // Draw neck
  3149.     dc.DrawLine((long) root.x, (long) root.y, (long) neck.x, (long) neck.y);
  3150.  
  3151.     if (count > 1)
  3152.     {
  3153.         // Draw shoulder-to-shoulder line
  3154.         dc.DrawLine((long) shoulder1.x, (long) shoulder1.y, (long) shoulder2.x, (long) shoulder2.y);
  3155.     }
  3156.     // Draw all the little branches
  3157.     int i;
  3158.     for (i = 0; i < count; i++)
  3159.     {
  3160.         wxRealPoint pt, stemPt;
  3161.         GetBranchingAttachmentPoint(attachment, i, pt, stemPt);
  3162.         dc.DrawLine((long) stemPt.x, (long) stemPt.y, (long) pt.x, (long) pt.y);
  3163.  
  3164.         if ((GetBranchStyle() & BRANCHING_ATTACHMENT_BLOB) && (count > 1))
  3165.         {
  3166.             long blobSize=6;
  3167. //            dc.DrawEllipse((long) (stemPt.x + 0.5 - (blobSize/2.0)), (long) (stemPt.y + 0.5 - (blobSize/2.0)), blobSize, blobSize);
  3168.             dc.DrawEllipse((long) (stemPt.x - (blobSize/2.0)), (long) (stemPt.y - (blobSize/2.0)), blobSize, blobSize);
  3169.         }
  3170.     }
  3171. }
  3172.  
  3173. // Draw or erase the branches (not the actual arcs though)
  3174. void wxShape::OnDrawBranches(wxDC& dc, bool erase)
  3175. {
  3176.     if (m_attachmentMode != ATTACHMENT_MODE_BRANCHING)
  3177.         return;
  3178.  
  3179.     int count = GetNumberOfAttachments();
  3180.     int i;
  3181.     for (i = 0; i < count; i++)
  3182.         OnDrawBranches(dc, i, erase);
  3183. }
  3184.  
  3185. // Only get the attachment position at the _edge_ of the shape, ignoring
  3186. // branching mode. This is used e.g. to indicate the edge of interest, not the point
  3187. // on the attachment branch.
  3188. bool wxShape::GetAttachmentPositionEdge(int attachment, double *x, double *y,
  3189.                                      int nth, int no_arcs, wxLineShape *line)
  3190. {
  3191.     int oldMode = m_attachmentMode;
  3192.  
  3193.     // Calculate as if to edge, not branch
  3194.     if (m_attachmentMode == ATTACHMENT_MODE_BRANCHING)
  3195.         m_attachmentMode = ATTACHMENT_MODE_EDGE;
  3196.     bool success = GetAttachmentPosition(attachment, x, y, nth, no_arcs, line);
  3197.     m_attachmentMode = oldMode;
  3198.  
  3199.     return success;
  3200. }
  3201.  
  3202. // Rotate the standard attachment point from physical (0 is always North)
  3203. // to logical (0 -> 1 if rotated by 90 degrees)
  3204. int wxShape::PhysicalToLogicalAttachment(int physicalAttachment) const
  3205. {
  3206.     const double pi = 3.1415926535897932384626433832795 ;
  3207.     int i;
  3208.     if (oglRoughlyEqual(GetRotation(), 0.0))
  3209.     {
  3210.         i = physicalAttachment;
  3211.     }
  3212.     else if (oglRoughlyEqual(GetRotation(), (pi/2.0)))
  3213.     {
  3214.         i = physicalAttachment - 1;
  3215.     }
  3216.     else if (oglRoughlyEqual(GetRotation(), pi))
  3217.     {
  3218.         i = physicalAttachment - 2;
  3219.     }
  3220.     else if (oglRoughlyEqual(GetRotation(), (3.0*pi/2.0)))
  3221.     {
  3222.         i = physicalAttachment - 3;
  3223.     }
  3224.     else
  3225.         // Can't handle -- assume the same.
  3226.         return physicalAttachment;
  3227.  
  3228.     if (i < 0)
  3229.       i += 4;
  3230.  
  3231.     return i;
  3232. }
  3233.  
  3234. // Rotate the standard attachment point from logical
  3235. // to physical (0 is always North)
  3236. int wxShape::LogicalToPhysicalAttachment(int logicalAttachment) const
  3237. {
  3238.     const double pi = 3.1415926535897932384626433832795 ;
  3239.     int i;
  3240.     if (oglRoughlyEqual(GetRotation(), 0.0))
  3241.     {
  3242.         i = logicalAttachment;
  3243.     }
  3244.     else if (oglRoughlyEqual(GetRotation(), (pi/2.0)))
  3245.     {
  3246.         i = logicalAttachment + 1;
  3247.     }
  3248.     else if (oglRoughlyEqual(GetRotation(), pi))
  3249.     {
  3250.         i = logicalAttachment + 2;
  3251.     }
  3252.     else if (oglRoughlyEqual(GetRotation(), (3.0*pi/2.0)))
  3253.     {
  3254.         i = logicalAttachment + 3;
  3255.     }
  3256.     else
  3257.         // Can't handle -- assume the same.
  3258.         return logicalAttachment;
  3259.  
  3260.     if (i > 3)
  3261.       i -= 4;
  3262.  
  3263.     return i;
  3264. }
  3265.  
  3266. void wxShape::Rotate(double WXUNUSED(x), double WXUNUSED(y), double theta)
  3267. {
  3268.     const double pi = 3.1415926535897932384626433832795 ;
  3269.     m_rotation = theta;
  3270.     if (m_rotation < 0.0)
  3271.     {
  3272.         m_rotation += 2*pi;
  3273.     }
  3274.     else if (m_rotation > 2*pi)
  3275.     {
  3276.         m_rotation -= 2*pi;
  3277.     }
  3278. }
  3279.  
  3280.  
  3281. wxPen wxShape::GetBackgroundPen()
  3282. {
  3283.     if (GetCanvas())
  3284.     {
  3285.         wxColour c = GetCanvas()->GetBackgroundColour();
  3286.         return wxPen(c, 1, wxSOLID);
  3287.     }
  3288.     return * g_oglWhiteBackgroundPen;
  3289. }
  3290.  
  3291.  
  3292. wxBrush wxShape::GetBackgroundBrush()
  3293. {
  3294.     if (GetCanvas())
  3295.     {
  3296.         wxColour c = GetCanvas()->GetBackgroundColour();
  3297.         return wxBrush(c, wxSOLID);
  3298.     }
  3299.     return * g_oglWhiteBackgroundBrush;
  3300. }
  3301.  
  3302.