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