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 / lines.cpp < prev    next >
C/C++ Source or Header  |  2002-12-28  |  72KB  |  2,516 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        lines.cpp
  3. // Purpose:     wxLineShape
  4. // Author:      Julian Smart
  5. // Modified by:
  6. // Created:     12/07/98
  7. // RCS-ID:      $Id: lines.cpp,v 1.6.2.3 2002/12/28 18:32:07 JS Exp $
  8. // Copyright:   (c) Julian Smart
  9. // Licence:       wxWindows licence
  10. /////////////////////////////////////////////////////////////////////////////
  11.  
  12. #ifdef __GNUG__
  13. #pragma implementation "lines.h"
  14. #pragma implementation "linesp.h"
  15. #endif
  16.  
  17. // For compilers that support precompilation, includes "wx.h".
  18. #include "wx/wxprec.h"
  19.  
  20. #ifdef __BORLANDC__
  21. #pragma hdrstop
  22. #endif
  23.  
  24. #ifndef WX_PRECOMP
  25. #include <wx/wx.h>
  26. #endif
  27.  
  28. #include <wx/wxexpr.h>
  29.  
  30. #ifdef new
  31. #undef new
  32. #endif
  33.  
  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/lines.h>
  40. #include <wx/ogl/linesp.h>
  41. #include <wx/ogl/drawn.h>
  42. #include <wx/ogl/misc.h>
  43. #include <wx/ogl/canvas.h>
  44.  
  45. // Line shape
  46. IMPLEMENT_DYNAMIC_CLASS(wxLineShape, wxShape)
  47.  
  48. wxLineShape::wxLineShape()
  49. {
  50.   m_sensitivity = OP_CLICK_LEFT | OP_CLICK_RIGHT;
  51.   m_draggable = FALSE;
  52.   m_attachmentTo = 0;
  53.   m_attachmentFrom = 0;
  54. /*
  55.   m_actualTextWidth = 0.0;
  56.   m_actualTextHeight = 0.0;
  57. */
  58.   m_from = NULL;
  59.   m_to = NULL;
  60.   m_erasing = FALSE;
  61.   m_arrowSpacing = 5.0; // For the moment, don't bother saving this to file.
  62.   m_ignoreArrowOffsets = FALSE;
  63.   m_isSpline = FALSE;
  64.   m_maintainStraightLines = FALSE;
  65.   m_alignmentStart = 0;
  66.   m_alignmentEnd = 0;
  67.  
  68.   m_lineControlPoints = NULL;
  69.  
  70.   // Clear any existing regions (created in an earlier constructor)
  71.   // and make the three line regions.
  72.   ClearRegions();
  73.   wxShapeRegion *newRegion = new wxShapeRegion;
  74.   newRegion->SetName(wxT("Middle"));
  75.   newRegion->SetSize(150, 50);
  76.   m_regions.Append((wxObject *)newRegion);
  77.  
  78.   newRegion = new wxShapeRegion;
  79.   newRegion->SetName(wxT("Start"));
  80.   newRegion->SetSize(150, 50);
  81.   m_regions.Append((wxObject *)newRegion);
  82.  
  83.   newRegion = new wxShapeRegion;
  84.   newRegion->SetName(wxT("End"));
  85.   newRegion->SetSize(150, 50);
  86.   m_regions.Append((wxObject *)newRegion);
  87.  
  88.   for (int i = 0; i < 3; i++)
  89.     m_labelObjects[i] = NULL;
  90. }
  91.  
  92. wxLineShape::~wxLineShape()
  93. {
  94.   if (m_lineControlPoints)
  95.   {
  96.     ClearPointList(*m_lineControlPoints);
  97.     delete m_lineControlPoints;
  98.   }
  99.   for (int i = 0; i < 3; i++)
  100.   {
  101.     if (m_labelObjects[i])
  102.     {
  103.       m_labelObjects[i]->Select(FALSE);
  104.       m_labelObjects[i]->RemoveFromCanvas(m_canvas);
  105.       delete m_labelObjects[i];
  106.       m_labelObjects[i] = NULL;
  107.     }
  108.   }
  109.   ClearArrowsAtPosition(-1);
  110. }
  111.  
  112. void wxLineShape::MakeLineControlPoints(int n)
  113. {
  114.   if (m_lineControlPoints)
  115.   {
  116.     ClearPointList(*m_lineControlPoints);
  117.     delete m_lineControlPoints;
  118.   }
  119.   m_lineControlPoints = new wxList;
  120.  
  121.   int i = 0;
  122.   for (i = 0; i < n; i++)
  123.   {
  124.     wxRealPoint *point = new wxRealPoint(-999, -999);
  125.     m_lineControlPoints->Append((wxObject*) point);
  126.   }
  127. }
  128.  
  129. wxNode *wxLineShape::InsertLineControlPoint(wxDC* dc)
  130. {
  131.     if (dc)
  132.         Erase(*dc);
  133.  
  134.   wxNode *last = m_lineControlPoints->Last();
  135.   wxNode *second_last = last->Previous();
  136.   wxRealPoint *last_point = (wxRealPoint *)last->Data();
  137.   wxRealPoint *second_last_point = (wxRealPoint *)second_last->Data();
  138.  
  139.   // Choose a point half way between the last and penultimate points
  140.   double line_x = ((last_point->x + second_last_point->x)/2);
  141.   double line_y = ((last_point->y + second_last_point->y)/2);
  142.  
  143.   wxRealPoint *point = new wxRealPoint(line_x, line_y);
  144.   wxNode *node = m_lineControlPoints->Insert(last, (wxObject*) point);
  145.   return node;
  146. }
  147.  
  148. bool wxLineShape::DeleteLineControlPoint()
  149. {
  150.   if (m_lineControlPoints->Number() < 3)
  151.     return FALSE;
  152.  
  153.   wxNode *last = m_lineControlPoints->Last();
  154.   wxNode *second_last = last->Previous();
  155.  
  156.   wxRealPoint *second_last_point = (wxRealPoint *)second_last->Data();
  157.   delete second_last_point;
  158.   delete second_last;
  159.  
  160.   return TRUE;
  161. }
  162.  
  163. void wxLineShape::Initialise()
  164. {
  165.   if (m_lineControlPoints)
  166.   {
  167.     // Just move the first and last control points
  168.     wxNode *first = m_lineControlPoints->First();
  169.     wxRealPoint *first_point = (wxRealPoint *)first->Data();
  170.  
  171.     wxNode *last = m_lineControlPoints->Last();
  172.     wxRealPoint *last_point = (wxRealPoint *)last->Data();
  173.  
  174.     // If any of the line points are at -999, we must
  175.     // initialize them by placing them half way between the first
  176.     // and the last.
  177.     wxNode *node = first->Next();
  178.     while (node)
  179.     {
  180.       wxRealPoint *point = (wxRealPoint *)node->Data();
  181.       if (point->x == -999)
  182.       {
  183.         double x1, y1, x2, y2;
  184.         if (first_point->x < last_point->x)
  185.           { x1 = first_point->x; x2 = last_point->x; }
  186.         else
  187.           { x2 = first_point->x; x1 = last_point->x; }
  188.  
  189.         if (first_point->y < last_point->y)
  190.           { y1 = first_point->y; y2 = last_point->y; }
  191.         else
  192.           { y2 = first_point->y; y1 = last_point->y; }
  193.  
  194.         point->x = ((x2 - x1)/2 + x1);
  195.         point->y = ((y2 - y1)/2 + y1);
  196.       }
  197.       node = node->Next();
  198.     }
  199.   }
  200. }
  201.  
  202. // Format a text string according to the region size, adding
  203. // strings with positions to region text list
  204. void wxLineShape::FormatText(wxDC& dc, const wxString& s, int i)
  205. {
  206.   double w, h;
  207.   ClearText(i);
  208.  
  209.   if (m_regions.Number() < 1)
  210.     return;
  211.   wxNode *node = m_regions.Nth(i);
  212.   if (!node)
  213.     return;
  214.  
  215.   wxShapeRegion *region = (wxShapeRegion *)node->Data();
  216.   region->SetText(s);
  217.   dc.SetFont(* region->GetFont());
  218.  
  219.   region->GetSize(&w, &h);
  220.   // Initialize the size if zero
  221.   if (((w == 0) || (h == 0)) && (s.Length() > 0))
  222.   {
  223.     w = 100; h = 50;
  224.     region->SetSize(w, h);
  225.   }
  226.  
  227.   wxStringList *string_list = oglFormatText(dc, s, (w-5), (h-5), region->GetFormatMode());
  228.   node = string_list->First();
  229.   while (node)
  230.   {
  231.     wxChar *s = (wxChar *)node->Data();
  232.     wxShapeTextLine *line = new wxShapeTextLine(0.0, 0.0, s);
  233.     region->GetFormattedText().Append((wxObject *)line);
  234.     node = node->Next();
  235.   }
  236.   delete string_list;
  237.   double actualW = w;
  238.   double actualH = h;
  239.   if (region->GetFormatMode() & FORMAT_SIZE_TO_CONTENTS)
  240.   {
  241.     oglGetCentredTextExtent(dc, &(region->GetFormattedText()), m_xpos, m_ypos, w, h, &actualW, &actualH);
  242.     if ((actualW != w ) || (actualH != h))
  243.     {
  244.       double xx, yy;
  245.       GetLabelPosition(i, &xx, &yy);
  246.       EraseRegion(dc, region, xx, yy);
  247.       if (m_labelObjects[i])
  248.       {
  249.         m_labelObjects[i]->Select(FALSE, &dc);
  250.         m_labelObjects[i]->Erase(dc);
  251.         m_labelObjects[i]->SetSize(actualW, actualH);
  252.       }
  253.  
  254.       region->SetSize(actualW, actualH);
  255.  
  256.       if (m_labelObjects[i])
  257.       {
  258.         m_labelObjects[i]->Select(TRUE, & dc);
  259.         m_labelObjects[i]->Draw(dc);
  260.       }
  261.     }
  262.   }
  263.   oglCentreText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, actualW, actualH, region->GetFormatMode());
  264.   m_formatted = TRUE;
  265. }
  266.  
  267. void wxLineShape::DrawRegion(wxDC& dc, wxShapeRegion *region, double x, double y)
  268. {
  269.   if (GetDisableLabel())
  270.     return;
  271.  
  272.   double w, h;
  273.   double xx, yy;
  274.   region->GetSize(&w, &h);
  275.  
  276.   // Get offset from x, y
  277.   region->GetPosition(&xx, &yy);
  278.  
  279.   double xp = xx + x;
  280.   double yp = yy + y;
  281.  
  282.   // First, clear a rectangle for the text IF there is any
  283.   if (region->GetFormattedText().Number() > 0)
  284.   {
  285.       dc.SetPen(GetBackgroundPen());
  286.       dc.SetBrush(GetBackgroundBrush());
  287.  
  288.       // Now draw the text
  289.       if (region->GetFont()) dc.SetFont(* region->GetFont());
  290.  
  291.       dc.DrawRectangle((long)(xp - w/2.0), (long)(yp - h/2.0), (long)w, (long)h);
  292.  
  293.       if (m_pen) dc.SetPen(* m_pen);
  294.       dc.SetTextForeground(* region->GetActualColourObject());
  295.  
  296. #ifdef __WXMSW__
  297.       dc.SetTextBackground(GetBackgroundBrush().GetColour());
  298. #endif
  299.  
  300.       oglDrawFormattedText(dc, &(region->GetFormattedText()), xp, yp, w, h, region->GetFormatMode());
  301.   }
  302. }
  303.  
  304. void wxLineShape::EraseRegion(wxDC& dc, wxShapeRegion *region, double x, double y)
  305. {
  306.   if (GetDisableLabel())
  307.     return;
  308.  
  309.   double w, h;
  310.   double xx, yy;
  311.   region->GetSize(&w, &h);
  312.  
  313.   // Get offset from x, y
  314.   region->GetPosition(&xx, &yy);
  315.  
  316.   double xp = xx + x;
  317.   double yp = yy + y;
  318.  
  319.   if (region->GetFormattedText().Number() > 0)
  320.   {
  321.       dc.SetPen(GetBackgroundPen());
  322.       dc.SetBrush(GetBackgroundBrush());
  323.  
  324.       dc.DrawRectangle((long)(xp - w/2.0), (long)(yp - h/2.0), (long)w, (long)h);
  325.   }
  326. }
  327.  
  328. // Get the reference point for a label. Region x and y
  329. // are offsets from this.
  330. // position is 0, 1, 2
  331. void wxLineShape::GetLabelPosition(int position, double *x, double *y)
  332. {
  333.   switch (position)
  334.   {
  335.     case 0:
  336.     {
  337.       // Want to take the middle section for the label
  338.       int n = m_lineControlPoints->Number();
  339.       int half_way = (int)(n/2);
  340.  
  341.       // Find middle of this line
  342.       wxNode *node = m_lineControlPoints->Nth(half_way - 1);
  343.       wxRealPoint *point = (wxRealPoint *)node->Data();
  344.       wxNode *next_node = node->Next();
  345.       wxRealPoint *next_point = (wxRealPoint *)next_node->Data();
  346.  
  347.       double dx = (next_point->x - point->x);
  348.       double dy = (next_point->y - point->y);
  349.       *x = (double)(point->x + dx/2.0);
  350.       *y = (double)(point->y + dy/2.0);
  351.       break;
  352.     }
  353.     case 1:
  354.     {
  355.       wxNode *node = m_lineControlPoints->First();
  356.       *x = ((wxRealPoint *)node->Data())->x;
  357.       *y = ((wxRealPoint *)node->Data())->y;
  358.       break;
  359.     }
  360.     case 2:
  361.     {
  362.       wxNode *node = m_lineControlPoints->Last();
  363.       *x = ((wxRealPoint *)node->Data())->x;
  364.       *y = ((wxRealPoint *)node->Data())->y;
  365.       break;
  366.     }
  367.     default:
  368.       break;
  369.   }
  370. }
  371.  
  372. /*
  373.  * Find whether line is supposed to be vertical or horizontal and
  374.  * make it so.
  375.  *
  376.  */
  377. void GraphicsStraightenLine(wxRealPoint *point1, wxRealPoint *point2)
  378. {
  379.   double dx = point2->x - point1->x;
  380.   double dy = point2->y - point1->y;
  381.  
  382.   if (dx == 0.0)
  383.     return;
  384.   else if (fabs(dy/dx) > 1.0)
  385.   {
  386.     point2->x = point1->x;
  387.   }
  388.   else point2->y = point1->y;
  389. }
  390.  
  391. void wxLineShape::Straighten(wxDC *dc)
  392. {
  393.   if (!m_lineControlPoints || m_lineControlPoints->Number() < 3)
  394.     return;
  395.  
  396.   if (dc)
  397.     Erase(* dc);
  398.  
  399.   wxNode *first_point_node = m_lineControlPoints->First();
  400.   wxNode *last_point_node = m_lineControlPoints->Last();
  401.   wxNode *second_last_point_node = last_point_node->Previous();
  402.  
  403.   wxRealPoint *last_point = (wxRealPoint *)last_point_node->Data();
  404.   wxRealPoint *second_last_point = (wxRealPoint *)second_last_point_node->Data();
  405.  
  406.   GraphicsStraightenLine(last_point, second_last_point);
  407.  
  408.   wxNode *node = first_point_node;
  409.   while (node && (node != second_last_point_node))
  410.   {
  411.     wxRealPoint *point = (wxRealPoint *)node->Data();
  412.     wxRealPoint *next_point = (wxRealPoint *)(node->Next()->Data());
  413.  
  414.     GraphicsStraightenLine(point, next_point);
  415.     node = node->Next();
  416.   }
  417.  
  418.   if (dc)
  419.     Draw(* dc);
  420. }
  421.  
  422.  
  423. void wxLineShape::Unlink()
  424. {
  425.   if (m_to)
  426.     m_to->GetLines().DeleteObject(this);
  427.   if (m_from)
  428.     m_from->GetLines().DeleteObject(this);
  429.   m_to = NULL;
  430.   m_from = NULL;
  431. }
  432.  
  433. void wxLineShape::SetEnds(double x1, double y1, double x2, double y2)
  434. {
  435.   // Find centre point
  436.   wxNode *first_point_node = m_lineControlPoints->First();
  437.   wxNode *last_point_node = m_lineControlPoints->Last();
  438.   wxRealPoint *first_point = (wxRealPoint *)first_point_node->Data();
  439.   wxRealPoint *last_point = (wxRealPoint *)last_point_node->Data();
  440.  
  441.   first_point->x = x1;
  442.   first_point->y = y1;
  443.   last_point->x = x2;
  444.   last_point->y = y2;
  445.  
  446.   m_xpos = (double)((x1 + x2)/2.0);
  447.   m_ypos = (double)((y1 + y2)/2.0);
  448. }
  449.  
  450. // Get absolute positions of ends
  451. void wxLineShape::GetEnds(double *x1, double *y1, double *x2, double *y2)
  452. {
  453.   wxNode *first_point_node = m_lineControlPoints->First();
  454.   wxNode *last_point_node = m_lineControlPoints->Last();
  455.   wxRealPoint *first_point = (wxRealPoint *)first_point_node->Data();
  456.   wxRealPoint *last_point = (wxRealPoint *)last_point_node->Data();
  457.  
  458.   *x1 = first_point->x; *y1 = first_point->y;
  459.   *x2 = last_point->x; *y2 = last_point->y;
  460. }
  461.  
  462. void wxLineShape::SetAttachments(int from_attach, int to_attach)
  463. {
  464.   m_attachmentFrom = from_attach;
  465.   m_attachmentTo = to_attach;
  466. }
  467.  
  468. bool wxLineShape::HitTest(double x, double y, int *attachment, double *distance)
  469. {
  470.   if (!m_lineControlPoints)
  471.     return FALSE;
  472.  
  473.   // Look at label regions in case mouse is over a label
  474.   bool inLabelRegion = FALSE;
  475.   for (int i = 0; i < 3; i ++)
  476.   {
  477.     wxNode *regionNode = m_regions.Nth(i);
  478.     if (regionNode)
  479.     {
  480.       wxShapeRegion *region = (wxShapeRegion *)regionNode->Data();
  481.       if (region->m_formattedText.Number() > 0)
  482.       {
  483.         double xp, yp, cx, cy, cw, ch;
  484.         GetLabelPosition(i, &xp, &yp);
  485.         // Offset region from default label position
  486.         region->GetPosition(&cx, &cy);
  487.         region->GetSize(&cw, &ch);
  488.         cx += xp;
  489.         cy += yp;
  490.         double rLeft = (double)(cx - (cw/2.0));
  491.         double rTop = (double)(cy - (ch/2.0));
  492.         double rRight = (double)(cx + (cw/2.0));
  493.         double rBottom = (double)(cy + (ch/2.0));
  494.         if (x > rLeft && x < rRight && y > rTop && y < rBottom)
  495.         {
  496.           inLabelRegion = TRUE;
  497.           i = 3;
  498.         }
  499.       }
  500.     }
  501.   }
  502.  
  503.   wxNode *node = m_lineControlPoints->First();
  504.  
  505.   while (node && node->Next())
  506.   {
  507.     wxRealPoint *point1 = (wxRealPoint *)node->Data();
  508.     wxRealPoint *point2 = (wxRealPoint *)node->Next()->Data();
  509.  
  510.     // Allow for inaccurate mousing or vert/horiz lines
  511.     int extra = 4;
  512.     double left = wxMin(point1->x, point2->x) - extra;
  513.     double right = wxMax(point1->x, point2->x) + extra;
  514.  
  515.     double bottom = wxMin(point1->y, point2->y) - extra;
  516.     double top = wxMax(point1->y, point2->y) + extra;
  517.  
  518.     if ((x > left && x < right && y > bottom && y < top) || inLabelRegion)
  519.     {
  520.       // Work out distance from centre of line
  521.       double centre_x = (double)(left + (right - left)/2.0);
  522.       double centre_y = (double)(bottom + (top - bottom)/2.0);
  523.  
  524.       *attachment = 0;
  525.       *distance = (double)sqrt((centre_x - x)*(centre_x - x) + (centre_y - y)*(centre_y - y));
  526.       return TRUE;
  527.     }
  528.  
  529.     node = node->Next();
  530.   }
  531.   return FALSE;
  532. }
  533.  
  534. void wxLineShape::DrawArrows(wxDC& dc)
  535. {
  536.   // Distance along line of each arrow: space them out evenly.
  537.   double startArrowPos = 0.0;
  538.   double endArrowPos = 0.0;
  539.   double middleArrowPos = 0.0;
  540.  
  541.   wxNode *node = m_arcArrows.First();
  542.   while (node)
  543.   {
  544.     wxArrowHead *arrow = (wxArrowHead *)node->Data();
  545.     switch (arrow->GetArrowEnd())
  546.     {
  547.       case ARROW_POSITION_START:
  548.       {
  549.         if ((arrow->GetXOffset() != 0.0) && !m_ignoreArrowOffsets)
  550.           // If specified, x offset is proportional to line length
  551.           DrawArrow(dc, arrow, arrow->GetXOffset(), TRUE);
  552.         else
  553.         {
  554.           DrawArrow(dc, arrow, startArrowPos, FALSE);      // Absolute distance
  555.           startArrowPos += arrow->GetSize() + arrow->GetSpacing();
  556.         }
  557.         break;
  558.       }
  559.       case ARROW_POSITION_END:
  560.       {
  561.         if ((arrow->GetXOffset() != 0.0) && !m_ignoreArrowOffsets)
  562.           DrawArrow(dc, arrow, arrow->GetXOffset(), TRUE);
  563.         else
  564.         {
  565.           DrawArrow(dc, arrow, endArrowPos, FALSE);
  566.           endArrowPos += arrow->GetSize() + arrow->GetSpacing();
  567.         }
  568.         break;
  569.       }
  570.       case ARROW_POSITION_MIDDLE:
  571.       {
  572.         arrow->SetXOffset(middleArrowPos);
  573.         if ((arrow->GetXOffset() != 0.0) && !m_ignoreArrowOffsets)
  574.           DrawArrow(dc, arrow, arrow->GetXOffset(), TRUE);
  575.         else
  576.         {
  577.           DrawArrow(dc, arrow, middleArrowPos, FALSE);
  578.           middleArrowPos += arrow->GetSize() + arrow->GetSpacing();
  579.         }
  580.         break;
  581.       }
  582.     }
  583.     node = node->Next();
  584.   }
  585. }
  586.  
  587. void wxLineShape::DrawArrow(wxDC& dc, wxArrowHead *arrow, double xOffset, bool proportionalOffset)
  588. {
  589.   wxNode *first_line_node = m_lineControlPoints->First();
  590.   wxRealPoint *first_line_point = (wxRealPoint *)first_line_node->Data();
  591.   wxNode *second_line_node = first_line_node->Next();
  592.   wxRealPoint *second_line_point = (wxRealPoint *)second_line_node->Data();
  593.  
  594.   wxNode *last_line_node = m_lineControlPoints->Last();
  595.   wxRealPoint *last_line_point = (wxRealPoint *)last_line_node->Data();
  596.   wxNode *second_last_line_node = last_line_node->Previous();
  597.   wxRealPoint *second_last_line_point = (wxRealPoint *)second_last_line_node->Data();
  598.  
  599.   // Position where we want to start drawing
  600.   double positionOnLineX, positionOnLineY;
  601.  
  602.   // Position of start point of line, at the end of which we draw the arrow.
  603.   double startPositionX, startPositionY;
  604.  
  605.   switch (arrow->GetPosition())
  606.   {
  607.     case ARROW_POSITION_START:
  608.     {
  609.       // If we're using a proportional offset, calculate just where this will
  610.       // be on the line.
  611.       double realOffset = xOffset;
  612.       if (proportionalOffset)
  613.       {
  614.         double totalLength =
  615.           (double)sqrt((second_line_point->x - first_line_point->x)*(second_line_point->x - first_line_point->x) +
  616.                       (second_line_point->y - first_line_point->y)*(second_line_point->y - first_line_point->y));
  617.         realOffset = (double)(xOffset * totalLength);
  618.       }
  619.       GetPointOnLine(second_line_point->x, second_line_point->y,
  620.                      first_line_point->x, first_line_point->y,
  621.                      realOffset, &positionOnLineX, &positionOnLineY);
  622.       startPositionX = second_line_point->x;
  623.       startPositionY = second_line_point->y;
  624.       break;
  625.     }
  626.     case ARROW_POSITION_END:
  627.     {
  628.       // If we're using a proportional offset, calculate just where this will
  629.       // be on the line.
  630.       double realOffset = xOffset;
  631.       if (proportionalOffset)
  632.       {
  633.         double totalLength =
  634.           (double)sqrt((second_last_line_point->x - last_line_point->x)*(second_last_line_point->x - last_line_point->x) +
  635.                       (second_last_line_point->y - last_line_point->y)*(second_last_line_point->y - last_line_point->y));
  636.         realOffset = (double)(xOffset * totalLength);
  637.       }
  638.       GetPointOnLine(second_last_line_point->x, second_last_line_point->y,
  639.                      last_line_point->x, last_line_point->y,
  640.                      realOffset, &positionOnLineX, &positionOnLineY);
  641.       startPositionX = second_last_line_point->x;
  642.       startPositionY = second_last_line_point->y;
  643.       break;
  644.     }
  645.     case ARROW_POSITION_MIDDLE:
  646.     {
  647.       // Choose a point half way between the last and penultimate points
  648.       double x = ((last_line_point->x + second_last_line_point->x)/2);
  649.       double y = ((last_line_point->y + second_last_line_point->y)/2);
  650.  
  651.       // If we're using a proportional offset, calculate just where this will
  652.       // be on the line.
  653.       double realOffset = xOffset;
  654.       if (proportionalOffset)
  655.       {
  656.         double totalLength =
  657.           (double)sqrt((second_last_line_point->x - x)*(second_last_line_point->x - x) +
  658.                       (second_last_line_point->y - y)*(second_last_line_point->y - y));
  659.         realOffset = (double)(xOffset * totalLength);
  660.       }
  661.  
  662.       GetPointOnLine(second_last_line_point->x, second_last_line_point->y,
  663.                      x, y, realOffset, &positionOnLineX, &positionOnLineY);
  664.       startPositionX = second_last_line_point->x;
  665.       startPositionY = second_last_line_point->y;
  666.       break;
  667.     }
  668.   }
  669.  
  670.   /*
  671.    * Add yOffset to arrow, if any
  672.    */
  673.  
  674.   const double myPi = (double) 3.14159265;
  675.   // The translation that the y offset may give
  676.   double deltaX = 0.0;
  677.   double deltaY = 0.0;
  678.   if ((arrow->GetYOffset() != 0.0) && !m_ignoreArrowOffsets)
  679.   {
  680.     /*
  681.                                  |(x4, y4)
  682.                                  |d
  683.                                  |
  684.        (x1, y1)--------------(x3, y3)------------------(x2, y2)
  685.        x4 = x3 - d * sin(theta)
  686.        y4 = y3 + d * cos(theta)
  687.  
  688.        Where theta = tan(-1) of (y3-y1)/(x3-x1)
  689.      */
  690.      double x1 = startPositionX;
  691.      double y1 = startPositionY;
  692.      double x3 = positionOnLineX;
  693.      double y3 = positionOnLineY;
  694.      double d = -arrow->GetYOffset(); // Negate so +offset is above line
  695.  
  696.      double theta = 0.0;
  697.      if (x3 == x1)
  698.        theta = (double)(myPi/2.0);
  699.      else
  700.        theta = (double)atan((y3-y1)/(x3-x1));
  701.  
  702.      double x4 = (double)(x3 - (d*sin(theta)));
  703.      double y4 = (double)(y3 + (d*cos(theta)));
  704.  
  705.      deltaX = x4 - positionOnLineX;
  706.      deltaY = y4 - positionOnLineY;
  707.   }
  708.  
  709.   switch (arrow->_GetType())
  710.   {
  711.     case ARROW_ARROW:
  712.     {
  713.       double arrowLength = arrow->GetSize();
  714.       double arrowWidth = (double)(arrowLength/3.0);
  715.  
  716.       double tip_x, tip_y, side1_x, side1_y, side2_x, side2_y;
  717.       oglGetArrowPoints(startPositionX+deltaX, startPositionY+deltaY,
  718.                        positionOnLineX+deltaX, positionOnLineY+deltaY,
  719.                        arrowLength, arrowWidth, &tip_x, &tip_y,
  720.                        &side1_x, &side1_y, &side2_x, &side2_y);
  721.  
  722.       wxPoint points[4];
  723.       points[0].x = (int) tip_x; points[0].y = (int) tip_y;
  724.       points[1].x = (int) side1_x; points[1].y = (int) side1_y;
  725.       points[2].x = (int) side2_x; points[2].y = (int) side2_y;
  726.       points[3].x = (int) tip_x; points[3].y = (int) tip_y;
  727.  
  728.       dc.SetPen(* m_pen);
  729.       dc.SetBrush(* m_brush);
  730.       dc.DrawPolygon(4, points);
  731.       break;
  732.     }
  733.     case ARROW_HOLLOW_CIRCLE:
  734.     case ARROW_FILLED_CIRCLE:
  735.     {
  736.       // Find point on line of centre of circle, which is a radius away
  737.       // from the end position
  738.       double diameter = (double)(arrow->GetSize());
  739.       double x, y;
  740.       GetPointOnLine(startPositionX+deltaX, startPositionY+deltaY,
  741.                    positionOnLineX+deltaX, positionOnLineY+deltaY,
  742.                    (double)(diameter/2.0),
  743.                    &x, &y);
  744.  
  745.       // Convert ellipse centre to top-left coordinates
  746.       double x1 = (double)(x - (diameter/2.0));
  747.       double y1 = (double)(y - (diameter/2.0));
  748.  
  749.       dc.SetPen(* m_pen);
  750.       if (arrow->_GetType() == ARROW_HOLLOW_CIRCLE)
  751.         dc.SetBrush(* g_oglWhiteBackgroundBrush);
  752.       else
  753.         dc.SetBrush(* m_brush);
  754.  
  755.       dc.DrawEllipse((long) x1, (long) y1, (long) diameter, (long) diameter);
  756.       break;
  757.     }
  758.     case ARROW_SINGLE_OBLIQUE:
  759.     {
  760.       break;
  761.     }
  762.     case ARROW_METAFILE:
  763.     {
  764.       if (arrow->GetMetaFile())
  765.       {
  766.         // Find point on line of centre of object, which is a half-width away
  767.         // from the end position
  768.         /*
  769.          *                width
  770.          * <-- start pos  <-----><-- positionOnLineX
  771.          *                _____
  772.          * --------------|  x  | <-- e.g. rectangular arrowhead
  773.          *                -----
  774.          */
  775.         double x, y;
  776.         GetPointOnLine(startPositionX, startPositionY,
  777.                    positionOnLineX, positionOnLineY,
  778.                    (double)(arrow->GetMetaFile()->m_width/2.0),
  779.                    &x, &y);
  780.  
  781.         // Calculate theta for rotating the metafile.
  782.         /*
  783.           |
  784.           |     o(x2, y2)   'o' represents the arrowhead.
  785.           |    /
  786.           |   /
  787.           |  /theta
  788.           | /(x1, y1)
  789.           |______________________
  790.         */
  791.         double theta = 0.0;
  792.         double x1 = startPositionX;
  793.         double y1 = startPositionY;
  794.         double x2 = positionOnLineX;
  795.         double y2 = positionOnLineY;
  796.  
  797.         if ((x1 == x2) && (y1 == y2))
  798.           theta = 0.0;
  799.  
  800.         else if ((x1 == x2) && (y1 > y2))
  801.           theta = (double)(3.0*myPi/2.0);
  802.  
  803.         else if ((x1 == x2) && (y2 > y1))
  804.           theta = (double)(myPi/2.0);
  805.  
  806.         else if ((x2 > x1) && (y2 >= y1))
  807.           theta = (double)atan((y2 - y1)/(x2 - x1));
  808.  
  809.         else if (x2 < x1)
  810.           theta = (double)(myPi + atan((y2 - y1)/(x2 - x1)));
  811.  
  812.         else if ((x2 > x1) && (y2 < y1))
  813.           theta = (double)(2*myPi + atan((y2 - y1)/(x2 - x1)));
  814.  
  815.         else
  816.         {
  817.           wxLogFatalError(wxT("Unknown arrowhead rotation case in lines.cc"));
  818.         }
  819.  
  820.         // Rotate about the centre of the object, then place
  821.         // the object on the line.
  822.         if (arrow->GetMetaFile()->GetRotateable())
  823.           arrow->GetMetaFile()->Rotate(0.0, 0.0, theta);
  824.  
  825.         if (m_erasing)
  826.         {
  827.           // If erasing, just draw a rectangle.
  828.           double minX, minY, maxX, maxY;
  829.           arrow->GetMetaFile()->GetBounds(&minX, &minY, &maxX, &maxY);
  830.           // Make erasing rectangle slightly bigger or you get droppings.
  831.           int extraPixels = 4;
  832.           dc.DrawRectangle((long)(deltaX + x + minX - (extraPixels/2.0)), (long)(deltaY + y + minY - (extraPixels/2.0)),
  833.                            (long)(maxX - minX + extraPixels), (long)(maxY - minY + extraPixels));
  834.         }
  835.         else
  836.           arrow->GetMetaFile()->Draw(dc, x+deltaX, y+deltaY);
  837.       }
  838.       break;
  839.     }
  840.     default:
  841.     {
  842.     }
  843.   }
  844. }
  845.  
  846. void wxLineShape::OnErase(wxDC& dc)
  847. {
  848.     wxPen *old_pen = m_pen;
  849.     wxBrush *old_brush = m_brush;
  850.     wxPen bg_pen = GetBackgroundPen();
  851.     wxBrush bg_brush = GetBackgroundBrush();
  852.     SetPen(&bg_pen);
  853.     SetBrush(&bg_brush);
  854.  
  855.     double bound_x, bound_y;
  856.     GetBoundingBoxMax(&bound_x, &bound_y);
  857.     if (m_font) dc.SetFont(* m_font);
  858.  
  859.     // Undraw text regions
  860.     for (int i = 0; i < 3; i++)
  861.     {
  862.       wxNode *node = m_regions.Nth(i);
  863.       if (node)
  864.       {
  865.         double x, y;
  866.         wxShapeRegion *region = (wxShapeRegion *)node->Data();
  867.         GetLabelPosition(i, &x, &y);
  868.         EraseRegion(dc, region, x, y);
  869.       }
  870.     }
  871.  
  872.     // Undraw line
  873.     dc.SetPen(GetBackgroundPen());
  874.     dc.SetBrush(GetBackgroundBrush());
  875.  
  876.     // Drawing over the line only seems to work if the line has a thickness
  877.     // of 1.
  878.     if (old_pen && (old_pen->GetWidth() > 1))
  879.     {
  880.       dc.DrawRectangle((long)(m_xpos - (bound_x/2.0) - 2.0), (long)(m_ypos - (bound_y/2.0) - 2.0),
  881.                         (long)(bound_x+4.0),  (long)(bound_y+4.0));
  882.     }
  883.     else
  884.     {
  885.       m_erasing = TRUE;
  886.       GetEventHandler()->OnDraw(dc);
  887.       GetEventHandler()->OnEraseControlPoints(dc);
  888.       m_erasing = FALSE;
  889.     }
  890.  
  891.     if (old_pen) SetPen(old_pen);
  892.     if (old_brush) SetBrush(old_brush);
  893. }
  894.  
  895. void wxLineShape::GetBoundingBoxMin(double *w, double *h)
  896. {
  897.   double x1 = 10000;
  898.   double y1 = 10000;
  899.   double x2 = -10000;
  900.   double y2 = -10000;
  901.  
  902.   wxNode *node = m_lineControlPoints->First();
  903.   while (node)
  904.   {
  905.     wxRealPoint *point = (wxRealPoint *)node->Data();
  906.  
  907.     if (point->x < x1) x1 = point->x;
  908.     if (point->y < y1) y1 = point->y;
  909.     if (point->x > x2) x2 = point->x;
  910.     if (point->y > y2) y2 = point->y;
  911.  
  912.     node = node->Next();
  913.   }
  914.   *w = (double)(x2 - x1);
  915.   *h = (double)(y2 - y1);
  916. }
  917.  
  918. /*
  919.  * For a node image of interest, finds the position of this arc
  920.  * amongst all the arcs which are attached to THIS SIDE of the node image,
  921.  * and the number of same.
  922.  */
  923. void wxLineShape::FindNth(wxShape *image, int *nth, int *no_arcs, bool incoming)
  924. {
  925.   int n = -1;
  926.   int num = 0;
  927.   wxNode *node = image->GetLines().First();
  928.   int this_attachment;
  929.   if (image == m_to)
  930.     this_attachment = m_attachmentTo;
  931.   else
  932.     this_attachment = m_attachmentFrom;
  933.  
  934.   // Find number of lines going into/out of this particular attachment point
  935.   while (node)
  936.   {
  937.     wxLineShape *line = (wxLineShape *)node->Data();
  938.  
  939.     if (line->m_from == image)
  940.     {
  941.       // This is the nth line attached to 'image'
  942.       if ((line == this) && !incoming)
  943.         n = num;
  944.  
  945.       // Increment num count if this is the same side (attachment number)
  946.       if (line->m_attachmentFrom == this_attachment)
  947.         num ++;
  948.     }
  949.  
  950.     if (line->m_to == image)
  951.     {
  952.       // This is the nth line attached to 'image'
  953.       if ((line == this) && incoming)
  954.         n = num;
  955.  
  956.       // Increment num count if this is the same side (attachment number)
  957.       if (line->m_attachmentTo == this_attachment)
  958.         num ++;
  959.     }
  960.  
  961.     node = node->Next();
  962.   }
  963.   *nth = n;
  964.   *no_arcs = num;
  965. }
  966.  
  967. void wxLineShape::OnDrawOutline(wxDC& dc, double x, double y, double w, double h)
  968. {
  969.   wxPen *old_pen = m_pen;
  970.   wxBrush *old_brush = m_brush;
  971.  
  972.   wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
  973.   SetPen(& dottedPen);
  974.   SetBrush( wxTRANSPARENT_BRUSH );
  975.  
  976.   GetEventHandler()->OnDraw(dc);
  977.  
  978.   if (old_pen) SetPen(old_pen);
  979.   else SetPen(NULL);
  980.   if (old_brush) SetBrush(old_brush);
  981.   else SetBrush(NULL);
  982. }
  983.  
  984. bool wxLineShape::OnMovePre(wxDC& dc, double x, double y, double old_x, double old_y, bool display)
  985. {
  986.   double x_offset = x - old_x;
  987.   double y_offset = y - old_y;
  988.  
  989.   if (m_lineControlPoints && !(x_offset == 0.0 && y_offset == 0.0))
  990.   {
  991.     wxNode *node = m_lineControlPoints->First();
  992.     while (node)
  993.     {
  994.       wxRealPoint *point = (wxRealPoint *)node->Data();
  995.       point->x += x_offset;
  996.       point->y += y_offset;
  997.       node = node->Next();
  998.     }
  999.  
  1000.   }
  1001.  
  1002.   // Move temporary label rectangles if necessary
  1003.   for (int i = 0; i < 3; i++)
  1004.   {
  1005.     if (m_labelObjects[i])
  1006.     {
  1007.       m_labelObjects[i]->Erase(dc);
  1008.       double xp, yp, xr, yr;
  1009.       GetLabelPosition(i, &xp, &yp);
  1010.       wxNode *node = m_regions.Nth(i);
  1011.       if (node)
  1012.       {
  1013.         wxShapeRegion *region = (wxShapeRegion *)node->Data();
  1014.         region->GetPosition(&xr, &yr);
  1015.       }
  1016.       else
  1017.       {
  1018.         xr = 0.0; yr = 0.0;
  1019.       }
  1020.  
  1021.       m_labelObjects[i]->Move(dc, xp+xr, yp+yr);
  1022.     }
  1023.   }
  1024.   return TRUE;
  1025. }
  1026.  
  1027. void wxLineShape::OnMoveLink(wxDC& dc, bool moveControlPoints)
  1028. {
  1029.   if (!m_from || !m_to)
  1030.    return;
  1031.  
  1032.     if (m_lineControlPoints->Number() > 2)
  1033.       Initialise();
  1034.  
  1035.     // Do each end - nothing in the middle. User has to move other points
  1036.     // manually if necessary.
  1037.     double end_x, end_y;
  1038.     double other_end_x, other_end_y;
  1039.  
  1040.     FindLineEndPoints(&end_x, &end_y, &other_end_x, &other_end_y);
  1041.  
  1042.     wxNode *first = m_lineControlPoints->First();
  1043.     wxRealPoint *first_point = (wxRealPoint *)first->Data();
  1044.     wxNode *last = m_lineControlPoints->Last();
  1045.     wxRealPoint *last_point = (wxRealPoint *)last->Data();
  1046.  
  1047. /* This is redundant, surely? Done by SetEnds.
  1048.     first_point->x = end_x; first_point->y = end_y;
  1049.     last_point->x = other_end_x; last_point->y = other_end_y;
  1050. */
  1051.  
  1052.     double oldX = m_xpos;
  1053.     double oldY = m_ypos;
  1054.  
  1055.     SetEnds(end_x, end_y, other_end_x, other_end_y);
  1056.  
  1057.     // Do a second time, because one may depend on the other.
  1058.     FindLineEndPoints(&end_x, &end_y, &other_end_x, &other_end_y);
  1059.     SetEnds(end_x, end_y, other_end_x, other_end_y);
  1060.  
  1061.     // Try to move control points with the arc
  1062.     double x_offset = m_xpos - oldX;
  1063.     double y_offset = m_ypos - oldY;
  1064.  
  1065. //    if (moveControlPoints && m_lineControlPoints && !(x_offset == 0.0 && y_offset == 0.0))
  1066.     // Only move control points if it's a self link. And only works if attachment mode is ON.
  1067.     if ((m_from == m_to) && (m_from->GetAttachmentMode() != ATTACHMENT_MODE_NONE) && moveControlPoints && m_lineControlPoints && !(x_offset == 0.0 && y_offset == 0.0))
  1068.     {
  1069.       wxNode *node = m_lineControlPoints->First();
  1070.       while (node)
  1071.       {
  1072.         if ((node != m_lineControlPoints->First()) && (node != m_lineControlPoints->Last()))
  1073.         {
  1074.           wxRealPoint *point = (wxRealPoint *)node->Data();
  1075.           point->x += x_offset;
  1076.           point->y += y_offset;
  1077.         }
  1078.         node = node->Next();
  1079.       }
  1080.     }
  1081.  
  1082.     Move(dc, m_xpos, m_ypos);
  1083. }
  1084.  
  1085. // Finds the x, y points at the two ends of the line.
  1086. // This function can be used by e.g. line-routing routines to
  1087. // get the actual points on the two node images where the lines will be drawn
  1088. // to/from.
  1089. void wxLineShape::FindLineEndPoints(double *fromX, double *fromY, double *toX, double *toY)
  1090. {
  1091.   if (!m_from || !m_to)
  1092.    return;
  1093.  
  1094.   // Do each end - nothing in the middle. User has to move other points
  1095.   // manually if necessary.
  1096.   double end_x, end_y;
  1097.   double other_end_x, other_end_y;
  1098.  
  1099.   wxNode *first = m_lineControlPoints->First();
  1100.   wxRealPoint *first_point = (wxRealPoint *)first->Data();
  1101.   wxNode *last = m_lineControlPoints->Last();
  1102.   wxRealPoint *last_point = (wxRealPoint *)last->Data();
  1103.  
  1104.   wxNode *second = first->Next();
  1105.   wxRealPoint *second_point = (wxRealPoint *)second->Data();
  1106.  
  1107.   wxNode *second_last = last->Previous();
  1108.   wxRealPoint *second_last_point = (wxRealPoint *)second_last->Data();
  1109.  
  1110.   if (m_lineControlPoints->Number() > 2)
  1111.   {
  1112.     if (m_from->GetAttachmentMode() != ATTACHMENT_MODE_NONE)
  1113.     {
  1114.       int nth, no_arcs;
  1115.       FindNth(m_from, &nth, &no_arcs, FALSE); // Not incoming
  1116.       m_from->GetAttachmentPosition(m_attachmentFrom, &end_x, &end_y, nth, no_arcs, this);
  1117.     }
  1118.     else
  1119.       (void) m_from->GetPerimeterPoint(m_from->GetX(), m_from->GetY(),
  1120.                                    (double)second_point->x, (double)second_point->y,
  1121.                                     &end_x, &end_y);
  1122.  
  1123.     if (m_to->GetAttachmentMode() != ATTACHMENT_MODE_NONE)
  1124.     {
  1125.       int nth, no_arcs;
  1126.       FindNth(m_to, &nth, &no_arcs, TRUE); // Incoming
  1127.       m_to->GetAttachmentPosition(m_attachmentTo, &other_end_x, &other_end_y, nth, no_arcs, this);
  1128.     }
  1129.     else
  1130.       (void) m_to->GetPerimeterPoint(m_to->GetX(), m_to->GetY(),
  1131.                                 (double)second_last_point->x, (double)second_last_point->y,
  1132.                                 &other_end_x, &other_end_y);
  1133.   }
  1134.   else
  1135.   {
  1136.     double fromX = m_from->GetX();
  1137.     double fromY = m_from->GetY();
  1138.     double toX = m_to->GetX();
  1139.     double toY = m_to->GetY();
  1140.  
  1141.     if (m_from->GetAttachmentMode() != ATTACHMENT_MODE_NONE)
  1142.     {
  1143.       int nth, no_arcs;
  1144.       FindNth(m_from, &nth, &no_arcs, FALSE);
  1145.       m_from->GetAttachmentPosition(m_attachmentFrom, &end_x, &end_y, nth, no_arcs, this);
  1146.       fromX = end_x;
  1147.       fromY = end_y;
  1148.     }
  1149.  
  1150.     if (m_to->GetAttachmentMode() != ATTACHMENT_MODE_NONE)
  1151.     {
  1152.       int nth, no_arcs;
  1153.       FindNth(m_to, &nth, &no_arcs, TRUE);
  1154.       m_to->GetAttachmentPosition(m_attachmentTo, &other_end_x, &other_end_y, nth, no_arcs, this);
  1155.       toX = other_end_x;
  1156.       toY = other_end_y;
  1157.     }
  1158.  
  1159.     if (m_from->GetAttachmentMode() == ATTACHMENT_MODE_NONE)
  1160.       (void) m_from->GetPerimeterPoint(m_from->GetX(), m_from->GetY(),
  1161.                                   toX, toY,
  1162.                                   &end_x, &end_y);
  1163.  
  1164.     if (m_to->GetAttachmentMode() == ATTACHMENT_MODE_NONE)
  1165.       (void) m_to->GetPerimeterPoint(m_to->GetX(), m_to->GetY(),
  1166.                                 fromX, fromY,
  1167.                                 &other_end_x, &other_end_y);
  1168.   }
  1169.   *fromX = end_x;
  1170.   *fromY = end_y;
  1171.   *toX = other_end_x;
  1172.   *toY = other_end_y;
  1173. }
  1174.  
  1175. void wxLineShape::OnDraw(wxDC& dc)
  1176. {
  1177.   if (m_lineControlPoints)
  1178.   {
  1179.     if (m_pen)
  1180.       dc.SetPen(* m_pen);
  1181.     if (m_brush)
  1182.       dc.SetBrush(* m_brush);
  1183.  
  1184.     int n = m_lineControlPoints->Number();
  1185.     wxPoint *points = new wxPoint[n];
  1186.     int i;
  1187.     for (i = 0; i < n; i++)
  1188.     {
  1189.         wxRealPoint* point = (wxRealPoint*) m_lineControlPoints->Nth(i)->Data();
  1190.         points[i].x = WXROUND(point->x);
  1191.         points[i].y = WXROUND(point->y);
  1192.     }
  1193.  
  1194.     if (m_isSpline)
  1195.       dc.DrawSpline(n, points);
  1196.     else
  1197.       dc.DrawLines(n, points);
  1198.  
  1199. #ifdef __WXMSW__
  1200.     // For some reason, last point isn't drawn under Windows.
  1201.     dc.DrawPoint(points[n-1]);
  1202. #endif
  1203.  
  1204.     delete[] points;
  1205.  
  1206.  
  1207.     // Problem with pen - if not a solid pen, does strange things
  1208.     // to the arrowhead. So make (get) a new pen that's solid.
  1209.     if (m_pen && (m_pen->GetStyle() != wxSOLID))
  1210.     {
  1211.       wxPen *solid_pen =
  1212.         wxThePenList->FindOrCreatePen(m_pen->GetColour(), 1, wxSOLID);
  1213.       if (solid_pen)
  1214.         dc.SetPen(* solid_pen);
  1215.     }
  1216.     DrawArrows(dc);
  1217.   }
  1218. }
  1219.  
  1220. void wxLineShape::OnDrawControlPoints(wxDC& dc)
  1221. {
  1222.   if (!m_drawHandles)
  1223.     return;
  1224.  
  1225.   // Draw temporary label rectangles if necessary
  1226.   for (int i = 0; i < 3; i++)
  1227.   {
  1228.     if (m_labelObjects[i])
  1229.       m_labelObjects[i]->Draw(dc);
  1230.   }
  1231.   wxShape::OnDrawControlPoints(dc);
  1232. }
  1233.  
  1234. void wxLineShape::OnEraseControlPoints(wxDC& dc)
  1235. {
  1236.   // Erase temporary label rectangles if necessary
  1237.   for (int i = 0; i < 3; i++)
  1238.   {
  1239.     if (m_labelObjects[i])
  1240.       m_labelObjects[i]->Erase(dc);
  1241.   }
  1242.   wxShape::OnEraseControlPoints(dc);
  1243. }
  1244.  
  1245. void wxLineShape::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
  1246. {
  1247. }
  1248.  
  1249. void wxLineShape::OnBeginDragLeft(double x, double y, int keys, int attachment)
  1250. {
  1251. }
  1252.  
  1253. void wxLineShape::OnEndDragLeft(double x, double y, int keys, int attachment)
  1254. {
  1255. }
  1256.  
  1257. /*
  1258. void wxLineShape::SetArrowSize(double length, double width)
  1259. {
  1260.   arrow_length = length;
  1261.   arrow_width = width;
  1262. }
  1263.  
  1264. void wxLineShape::SetStartArrow(int style)
  1265. {
  1266.   start_style = style;
  1267. }
  1268.  
  1269. void wxLineShape::SetMiddleArrow(int style)
  1270. {
  1271.   middle_style = style;
  1272. }
  1273.  
  1274. void wxLineShape::SetEndArrow(int style)
  1275. {
  1276.   end_style = style;
  1277. }
  1278. */
  1279.  
  1280. void wxLineShape::OnDrawContents(wxDC& dc)
  1281. {
  1282.   if (GetDisableLabel())
  1283.     return;
  1284.  
  1285.   for (int i = 0; i < 3; i++)
  1286.   {
  1287.     wxNode *node = m_regions.Nth(i);
  1288.     if (node)
  1289.     {
  1290.       wxShapeRegion *region = (wxShapeRegion *)node->Data();
  1291.       double x, y;
  1292.       GetLabelPosition(i, &x, &y);
  1293.       DrawRegion(dc, region, x, y);
  1294.     }
  1295.   }
  1296. }
  1297.  
  1298. void wxLineShape::SetTo(wxShape *object)
  1299. {
  1300.   m_to = object;
  1301. }
  1302.  
  1303. void wxLineShape::SetFrom(wxShape *object)
  1304. {
  1305.   m_from = object;
  1306. }
  1307.  
  1308. void wxLineShape::MakeControlPoints()
  1309. {
  1310.   if (m_canvas && m_lineControlPoints)
  1311.   {
  1312.     wxNode *first = m_lineControlPoints->First();
  1313.     wxNode *last = m_lineControlPoints->Last();
  1314.     wxRealPoint *first_point = (wxRealPoint *)first->Data();
  1315.     wxRealPoint *last_point = (wxRealPoint *)last->Data();
  1316.  
  1317.     wxLineControlPoint *control = new wxLineControlPoint(m_canvas, this, CONTROL_POINT_SIZE,
  1318.                                                first_point->x, first_point->y,
  1319.                                                CONTROL_POINT_ENDPOINT_FROM);
  1320.     control->m_point = first_point;
  1321.     m_canvas->AddShape(control);
  1322.     m_controlPoints.Append(control);
  1323.  
  1324.  
  1325.     wxNode *node = first->Next();
  1326.     while (node != last)
  1327.     {
  1328.       wxRealPoint *point = (wxRealPoint *)node->Data();
  1329.  
  1330.       control = new wxLineControlPoint(m_canvas, this, CONTROL_POINT_SIZE,
  1331.                                                point->x, point->y,
  1332.                                                CONTROL_POINT_LINE);
  1333.       control->m_point = point;
  1334.  
  1335.       m_canvas->AddShape(control);
  1336.       m_controlPoints.Append(control);
  1337.  
  1338.       node = node->Next();
  1339.     }
  1340.     control = new wxLineControlPoint(m_canvas, this, CONTROL_POINT_SIZE,
  1341.                                                last_point->x, last_point->y,
  1342.                                                CONTROL_POINT_ENDPOINT_TO);
  1343.     control->m_point = last_point;
  1344.     m_canvas->AddShape(control);
  1345.     m_controlPoints.Append(control);
  1346.  
  1347.   }
  1348.  
  1349. }
  1350.  
  1351. void wxLineShape::ResetControlPoints()
  1352. {
  1353.   if (m_canvas && m_lineControlPoints && m_controlPoints.Number() > 0)
  1354.   {
  1355.     wxNode *node = m_controlPoints.First();
  1356.     wxNode *control_node = m_lineControlPoints->First();
  1357.     while (node && control_node)
  1358.     {
  1359.       wxRealPoint *point = (wxRealPoint *)control_node->Data();
  1360.       wxLineControlPoint *control = (wxLineControlPoint *)node->Data();
  1361.       control->SetX(point->x);
  1362.       control->SetY(point->y);
  1363.  
  1364.       node = node->Next();
  1365.       control_node = control_node->Next();
  1366.     }
  1367.   }
  1368. }
  1369.  
  1370. #if wxUSE_PROLOGIO
  1371. void wxLineShape::WriteAttributes(wxExpr *clause)
  1372. {
  1373.   wxShape::WriteAttributes(clause);
  1374.  
  1375.   if (m_from)
  1376.     clause->AddAttributeValue("from", m_from->GetId());
  1377.   if (m_to)
  1378.     clause->AddAttributeValue("to", m_to->GetId());
  1379.  
  1380.   if (m_attachmentTo != 0)
  1381.     clause->AddAttributeValue("attachment_to", (long)m_attachmentTo);
  1382.   if (m_attachmentFrom != 0)
  1383.     clause->AddAttributeValue("attachment_from", (long)m_attachmentFrom);
  1384.  
  1385.   if (m_alignmentStart != 0)
  1386.     clause->AddAttributeValue("align_start", (long)m_alignmentStart);
  1387.   if (m_alignmentEnd != 0)
  1388.     clause->AddAttributeValue("align_end", (long)m_alignmentEnd);
  1389.  
  1390.   clause->AddAttributeValue("is_spline", (long)m_isSpline);
  1391.   if (m_maintainStraightLines)
  1392.     clause->AddAttributeValue("keep_lines_straight", (long)m_maintainStraightLines);
  1393.  
  1394.   // Make a list of lists for the (sp)line controls
  1395.   wxExpr *list = new wxExpr(wxExprList);
  1396.   wxNode *node = m_lineControlPoints->First();
  1397.   while (node)
  1398.   {
  1399.     wxRealPoint *point = (wxRealPoint *)node->Data();
  1400.     wxExpr *point_list = new wxExpr(wxExprList);
  1401.     wxExpr *x_expr = new wxExpr((double) point->x);
  1402.     wxExpr *y_expr = new wxExpr((double) point->y);
  1403.     point_list->Append(x_expr);
  1404.     point_list->Append(y_expr);
  1405.     list->Append(point_list);
  1406.  
  1407.     node = node->Next();
  1408.   }
  1409.   clause->AddAttributeValue("controls", list);
  1410.  
  1411.   // Write arc arrows in new OGL format, if there are any.
  1412.   // This is a list of lists. Each sublist comprises:
  1413.   // (arrowType arrowEnd xOffset arrowSize)
  1414.   if (m_arcArrows.Number() > 0)
  1415.   {
  1416.     wxExpr *arrow_list = new wxExpr(wxExprList);
  1417.     node = m_arcArrows.First();
  1418.     while (node)
  1419.     {
  1420.       wxArrowHead *head = (wxArrowHead *)node->Data();
  1421.       wxExpr *head_list = new wxExpr(wxExprList);
  1422.       head_list->Append(new wxExpr((long)head->_GetType()));
  1423.       head_list->Append(new wxExpr((long)head->GetArrowEnd()));
  1424.       head_list->Append(new wxExpr(head->GetXOffset()));
  1425.       head_list->Append(new wxExpr(head->GetArrowSize()));
  1426.       head_list->Append(new wxExpr(wxExprString, head->GetName()));
  1427.       head_list->Append(new wxExpr(head->GetId()));
  1428.  
  1429.       // New members of wxArrowHead
  1430.       head_list->Append(new wxExpr(head->GetYOffset()));
  1431.       head_list->Append(new wxExpr(head->GetSpacing()));
  1432.  
  1433.       arrow_list->Append(head_list);
  1434.  
  1435.       node = node->Next();
  1436.     }
  1437.     clause->AddAttributeValue("arrows", arrow_list);
  1438.   }
  1439. }
  1440.  
  1441. void wxLineShape::ReadAttributes(wxExpr *clause)
  1442. {
  1443.   wxShape::ReadAttributes(clause);
  1444.  
  1445.   int iVal = (int) m_isSpline;
  1446.   clause->AssignAttributeValue(wxT("is_spline"), &iVal);
  1447.   m_isSpline = (iVal != 0);
  1448.  
  1449.   iVal = (int) m_maintainStraightLines;
  1450.   clause->AssignAttributeValue(wxT("keep_lines_straight"), &iVal);
  1451.   m_maintainStraightLines = (iVal != 0);
  1452.  
  1453.   clause->AssignAttributeValue(wxT("align_start"), &m_alignmentStart);
  1454.   clause->AssignAttributeValue(wxT("align_end"), &m_alignmentEnd);
  1455.  
  1456.   // Compatibility: check for no regions.
  1457.   if (m_regions.Number() == 0)
  1458.   {
  1459.     wxShapeRegion *newRegion = new wxShapeRegion;
  1460.     newRegion->SetName("Middle");
  1461.     newRegion->SetSize(150, 50);
  1462.     m_regions.Append((wxObject *)newRegion);
  1463.     if (m_text.Number() > 0)
  1464.     {
  1465.       newRegion->ClearText();
  1466.       wxNode *node = m_text.First();
  1467.       while (node)
  1468.       {
  1469.         wxShapeTextLine *textLine = (wxShapeTextLine *)node->Data();
  1470.         wxNode *next = node->Next();
  1471.         newRegion->GetFormattedText().Append((wxObject *)textLine);
  1472.         delete node;
  1473.         node = next;
  1474.       }
  1475.     }
  1476.  
  1477.     newRegion = new wxShapeRegion;
  1478.     newRegion->SetName(wxT("Start"));
  1479.     newRegion->SetSize(150, 50);
  1480.     m_regions.Append((wxObject *)newRegion);
  1481.  
  1482.     newRegion = new wxShapeRegion;
  1483.     newRegion->SetName(wxT("End"));
  1484.     newRegion->SetSize(150, 50);
  1485.     m_regions.Append((wxObject *)newRegion);
  1486.   }
  1487.  
  1488.   m_attachmentTo = 0;
  1489.   m_attachmentFrom = 0;
  1490.  
  1491.   clause->AssignAttributeValue(wxT("attachment_to"), &m_attachmentTo);
  1492.   clause->AssignAttributeValue(wxT("attachment_from"), &m_attachmentFrom);
  1493.  
  1494.   wxExpr *line_list = NULL;
  1495.  
  1496.   // When image is created, there are default control points. Override
  1497.   // them if there are some in the file.
  1498.   clause->AssignAttributeValue(wxT("controls"), &line_list);
  1499.  
  1500.   if (line_list)
  1501.   {
  1502.     // Read a list of lists for the spline controls
  1503.     if (m_lineControlPoints)
  1504.     {
  1505.       ClearPointList(*m_lineControlPoints);
  1506.     }
  1507.     else
  1508.       m_lineControlPoints = new wxList;
  1509.  
  1510.     wxExpr *node = line_list->value.first;
  1511.  
  1512.     while (node)
  1513.     {
  1514.       wxExpr *xexpr = node->value.first;
  1515.       double x = xexpr->RealValue();
  1516.  
  1517.       wxExpr *yexpr = xexpr->next;
  1518.       double y = yexpr->RealValue();
  1519.  
  1520.       wxRealPoint *point = new wxRealPoint(x, y);
  1521.       m_lineControlPoints->Append((wxObject*) point);
  1522.  
  1523.       node = node->next;
  1524.     }
  1525.   }
  1526.  
  1527.   // Read arrow list, for new OGL code
  1528.   wxExpr *arrow_list = NULL;
  1529.  
  1530.   clause->AssignAttributeValue(wxT("arrows"), &arrow_list);
  1531.   if (arrow_list)
  1532.   {
  1533.     wxExpr *node = arrow_list->value.first;
  1534.  
  1535.     while (node)
  1536.     {
  1537.       WXTYPE arrowType = ARROW_ARROW;
  1538.       int arrowEnd = 0;
  1539.       double xOffset = 0.0;
  1540.       double arrowSize = 0.0;
  1541.       wxString arrowName;
  1542.       long arrowId = -1;
  1543.  
  1544.       wxExpr *type_expr = node->Nth(0);
  1545.       wxExpr *end_expr = node->Nth(1);
  1546.       wxExpr *dist_expr = node->Nth(2);
  1547.       wxExpr *size_expr = node->Nth(3);
  1548.       wxExpr *name_expr = node->Nth(4);
  1549.       wxExpr *id_expr = node->Nth(5);
  1550.  
  1551.       // New members of wxArrowHead
  1552.       wxExpr *yOffsetExpr = node->Nth(6);
  1553.       wxExpr *spacingExpr = node->Nth(7);
  1554.  
  1555.       if (type_expr)
  1556.         arrowType = (int)type_expr->IntegerValue();
  1557.       if (end_expr)
  1558.         arrowEnd = (int)end_expr->IntegerValue();
  1559.       if (dist_expr)
  1560.         xOffset = dist_expr->RealValue();
  1561.       if (size_expr)
  1562.         arrowSize = size_expr->RealValue();
  1563.       if (name_expr)
  1564.         arrowName = name_expr->StringValue();
  1565.       if (id_expr)
  1566.         arrowId = id_expr->IntegerValue();
  1567.  
  1568.       if (arrowId == -1)
  1569.         arrowId = wxNewId();
  1570.       else
  1571.         wxRegisterId(arrowId);
  1572.  
  1573.       wxArrowHead *arrowHead = AddArrow(arrowType, arrowEnd, arrowSize, xOffset, arrowName, NULL, arrowId);
  1574.       if (yOffsetExpr)
  1575.         arrowHead->SetYOffset(yOffsetExpr->RealValue());
  1576.       if (spacingExpr)
  1577.         arrowHead->SetSpacing(spacingExpr->RealValue());
  1578.  
  1579.       node = node->next;
  1580.     }
  1581.   }
  1582. }
  1583. #endif
  1584.  
  1585. void wxLineShape::Copy(wxShape& copy)
  1586. {
  1587.   wxShape::Copy(copy);
  1588.  
  1589.   wxASSERT( copy.IsKindOf(CLASSINFO(wxLineShape)) );
  1590.  
  1591.   wxLineShape& lineCopy = (wxLineShape&) copy;
  1592.  
  1593.   lineCopy.m_to = m_to;
  1594.   lineCopy.m_from = m_from;
  1595.   lineCopy.m_attachmentTo = m_attachmentTo;
  1596.   lineCopy.m_attachmentFrom = m_attachmentFrom;
  1597.   lineCopy.m_isSpline = m_isSpline;
  1598.   lineCopy.m_alignmentStart = m_alignmentStart;
  1599.   lineCopy.m_alignmentEnd = m_alignmentEnd;
  1600.   lineCopy.m_maintainStraightLines = m_maintainStraightLines;
  1601.   lineCopy.m_lineOrientations.Clear();
  1602.  
  1603.   wxNode *node = m_lineOrientations.First();
  1604.   while (node)
  1605.   {
  1606.     lineCopy.m_lineOrientations.Append(node->Data());
  1607.     node = node->Next();
  1608.   }
  1609.  
  1610.   if (lineCopy.m_lineControlPoints)
  1611.   {
  1612.     ClearPointList(*lineCopy.m_lineControlPoints);
  1613.     delete lineCopy.m_lineControlPoints;
  1614.   }
  1615.  
  1616.   lineCopy.m_lineControlPoints = new wxList;
  1617.  
  1618.   node = m_lineControlPoints->First();
  1619.   while (node)
  1620.   {
  1621.     wxRealPoint *point = (wxRealPoint *)node->Data();
  1622.     wxRealPoint *new_point = new wxRealPoint(point->x, point->y);
  1623.     lineCopy.m_lineControlPoints->Append((wxObject*) new_point);
  1624.     node = node->Next();
  1625.   }
  1626.  
  1627.   // Copy arrows
  1628.   lineCopy.ClearArrowsAtPosition(-1);
  1629.   node = m_arcArrows.First();
  1630.   while (node)
  1631.   {
  1632.     wxArrowHead *arrow = (wxArrowHead *)node->Data();
  1633.     lineCopy.m_arcArrows.Append(new wxArrowHead(*arrow));
  1634.     node = node->Next();
  1635.   }
  1636. }
  1637.  
  1638. // Override select, to create/delete temporary label-moving objects
  1639. void wxLineShape::Select(bool select, wxDC* dc)
  1640. {
  1641.   wxShape::Select(select, dc);
  1642.   if (select)
  1643.   {
  1644.     for (int i = 0; i < 3; i++)
  1645.     {
  1646.       wxNode *node = m_regions.Nth(i);
  1647.       if (node)
  1648.       {
  1649.         wxShapeRegion *region = (wxShapeRegion *)node->Data();
  1650.         if (region->m_formattedText.Number() > 0)
  1651.         {
  1652.           double w, h, x, y, xx, yy;
  1653.           region->GetSize(&w, &h);
  1654.           region->GetPosition(&x, &y);
  1655.           GetLabelPosition(i, &xx, &yy);
  1656.           if (m_labelObjects[i])
  1657.           {
  1658.             m_labelObjects[i]->Select(FALSE);
  1659.             m_labelObjects[i]->RemoveFromCanvas(m_canvas);
  1660.             delete m_labelObjects[i];
  1661.           }
  1662.           m_labelObjects[i] = OnCreateLabelShape(this, region, w, h);
  1663.           m_labelObjects[i]->AddToCanvas(m_canvas);
  1664.           m_labelObjects[i]->Show(TRUE);
  1665.           if (dc)
  1666.             m_labelObjects[i]->Move(*dc, (double)(x + xx), (double)(y + yy));
  1667.           m_labelObjects[i]->Select(TRUE, dc);
  1668.         }
  1669.       }
  1670.     }
  1671.   }
  1672.   else
  1673.   {
  1674.     for (int i = 0; i < 3; i++)
  1675.     {
  1676.       if (m_labelObjects[i])
  1677.       {
  1678.         m_labelObjects[i]->Select(FALSE, dc);
  1679.         m_labelObjects[i]->Erase(*dc);
  1680.         m_labelObjects[i]->RemoveFromCanvas(m_canvas);
  1681.         delete m_labelObjects[i];
  1682.         m_labelObjects[i] = NULL;
  1683.       }
  1684.     }
  1685.   }
  1686. }
  1687.  
  1688. /*
  1689.  * Line control point
  1690.  *
  1691.  */
  1692.  
  1693. IMPLEMENT_DYNAMIC_CLASS(wxLineControlPoint, wxControlPoint)
  1694.  
  1695. wxLineControlPoint::wxLineControlPoint(wxShapeCanvas *theCanvas, wxShape *object, double size, double x, double y, int the_type):
  1696.   wxControlPoint(theCanvas, object, size, x, y, the_type)
  1697. {
  1698.   m_xpos = x;
  1699.   m_ypos = y;
  1700.   m_type = the_type;
  1701.   m_point = NULL;
  1702. }
  1703.  
  1704. wxLineControlPoint::~wxLineControlPoint()
  1705. {
  1706. }
  1707.  
  1708. void wxLineControlPoint::OnDraw(wxDC& dc)
  1709. {
  1710.   wxRectangleShape::OnDraw(dc);
  1711. }
  1712.  
  1713. // Implement movement of Line point
  1714. void wxLineControlPoint::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
  1715. {
  1716.     m_shape->GetEventHandler()->OnSizingDragLeft(this, draw, x, y, keys, attachment);
  1717. }
  1718.  
  1719. void wxLineControlPoint::OnBeginDragLeft(double x, double y, int keys, int attachment)
  1720. {
  1721.     m_shape->GetEventHandler()->OnSizingBeginDragLeft(this, x, y, keys, attachment);
  1722. }
  1723.  
  1724. void wxLineControlPoint::OnEndDragLeft(double x, double y, int keys, int attachment)
  1725. {
  1726.     m_shape->GetEventHandler()->OnSizingEndDragLeft(this, x, y, keys, attachment);
  1727. }
  1728.  
  1729. // Control points ('handles') redirect control to the actual shape, to make it easier
  1730. // to override sizing behaviour.
  1731. void wxLineShape::OnSizingDragLeft(wxControlPoint* pt, bool draw, double x, double y, int keys, int attachment)
  1732. {
  1733.   wxLineControlPoint* lpt = (wxLineControlPoint*) pt;
  1734.  
  1735.   wxClientDC dc(GetCanvas());
  1736.   GetCanvas()->PrepareDC(dc);
  1737.  
  1738.   dc.SetLogicalFunction(OGLRBLF);
  1739.  
  1740.   wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
  1741.   dc.SetPen(dottedPen);
  1742.   dc.SetBrush((* wxTRANSPARENT_BRUSH));
  1743.  
  1744.   if (lpt->m_type == CONTROL_POINT_LINE)
  1745.   {
  1746.     m_canvas->Snap(&x, &y);
  1747.  
  1748.     lpt->SetX(x); lpt->SetY(y);
  1749.     lpt->m_point->x = x; lpt->m_point->y = y;
  1750.  
  1751.     wxLineShape *lineShape = (wxLineShape *)this;
  1752.  
  1753.     wxPen *old_pen = lineShape->GetPen();
  1754.     wxBrush *old_brush = lineShape->GetBrush();
  1755.  
  1756.     wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
  1757.     lineShape->SetPen(& dottedPen);
  1758.     lineShape->SetBrush(wxTRANSPARENT_BRUSH);
  1759.  
  1760.     lineShape->GetEventHandler()->OnMoveLink(dc, FALSE);
  1761.  
  1762.     lineShape->SetPen(old_pen);
  1763.     lineShape->SetBrush(old_brush);
  1764.   }
  1765.  
  1766.   if (lpt->m_type == CONTROL_POINT_ENDPOINT_FROM || lpt->m_type == CONTROL_POINT_ENDPOINT_TO)
  1767.   {
  1768. //    lpt->SetX(x); lpt->SetY(y);
  1769.   }
  1770.  
  1771. }
  1772.  
  1773. void wxLineShape::OnSizingBeginDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment)
  1774. {
  1775.   wxLineControlPoint* lpt = (wxLineControlPoint*) pt;
  1776.  
  1777.   wxClientDC dc(GetCanvas());
  1778.   GetCanvas()->PrepareDC(dc);
  1779.  
  1780.   wxLineShape *lineShape = (wxLineShape *)this;
  1781.   if (lpt->m_type == CONTROL_POINT_LINE)
  1782.   {
  1783.     lpt->m_originalPos = * (lpt->m_point);
  1784.     m_canvas->Snap(&x, &y);
  1785.  
  1786.     this->Erase(dc);
  1787.  
  1788.     // Redraw start and end objects because we've left holes
  1789.     // when erasing the line
  1790.     lineShape->GetFrom()->OnDraw(dc);
  1791.     lineShape->GetFrom()->OnDrawContents(dc);
  1792.     lineShape->GetTo()->OnDraw(dc);
  1793.     lineShape->GetTo()->OnDrawContents(dc);
  1794.  
  1795.     this->SetDisableLabel(TRUE);
  1796.     dc.SetLogicalFunction(OGLRBLF);
  1797.  
  1798.     lpt->m_xpos = x; lpt->m_ypos = y;
  1799.     lpt->m_point->x = x; lpt->m_point->y = y;
  1800.  
  1801.     wxPen *old_pen = lineShape->GetPen();
  1802.     wxBrush *old_brush = lineShape->GetBrush();
  1803.  
  1804.     wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
  1805.     lineShape->SetPen(& dottedPen);
  1806.     lineShape->SetBrush(wxTRANSPARENT_BRUSH);
  1807.  
  1808.     lineShape->GetEventHandler()->OnMoveLink(dc, FALSE);
  1809.  
  1810.     lineShape->SetPen(old_pen);
  1811.     lineShape->SetBrush(old_brush);
  1812.   }
  1813.  
  1814.   if (lpt->m_type == CONTROL_POINT_ENDPOINT_FROM || lpt->m_type == CONTROL_POINT_ENDPOINT_TO)
  1815.   {
  1816.     m_canvas->SetCursor(wxCursor(wxCURSOR_BULLSEYE));
  1817.     lpt->m_oldCursor = wxSTANDARD_CURSOR;
  1818.   }
  1819. }
  1820.  
  1821. void wxLineShape::OnSizingEndDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment)
  1822. {
  1823.   wxLineControlPoint* lpt = (wxLineControlPoint*) pt;
  1824.  
  1825.   wxClientDC dc(GetCanvas());
  1826.   GetCanvas()->PrepareDC(dc);
  1827.  
  1828.   this->SetDisableLabel(FALSE);
  1829.   wxLineShape *lineShape = (wxLineShape *)this;
  1830.  
  1831.   if (lpt->m_type == CONTROL_POINT_LINE)
  1832.   {
  1833.     m_canvas->Snap(&x, &y);
  1834.  
  1835.     wxRealPoint pt = wxRealPoint(x, y);
  1836.  
  1837.     // Move the control point back to where it was;
  1838.     // MoveControlPoint will move it to the new position
  1839.     // if it decides it wants. We only moved the position
  1840.     // during user feedback so we could redraw the line
  1841.     // as it changed shape.
  1842.     lpt->m_xpos = lpt->m_originalPos.x; lpt->m_ypos = lpt->m_originalPos.y;
  1843.     lpt->m_point->x = lpt->m_originalPos.x; lpt->m_point->y = lpt->m_originalPos.y;
  1844.  
  1845.     OnMoveMiddleControlPoint(dc, lpt, pt);
  1846.   }
  1847.   if (lpt->m_type == CONTROL_POINT_ENDPOINT_FROM)
  1848.   {
  1849.     if (lpt->m_oldCursor)
  1850.       m_canvas->SetCursor(* lpt->m_oldCursor);
  1851.  
  1852. //    this->Erase(dc);
  1853.  
  1854. //    lpt->m_xpos = x; lpt->m_ypos = y;
  1855.  
  1856.     if (lineShape->GetFrom())
  1857.     {
  1858.       lineShape->GetFrom()->MoveLineToNewAttachment(dc, lineShape, x, y);
  1859.     }
  1860.   }
  1861.   if (lpt->m_type == CONTROL_POINT_ENDPOINT_TO)
  1862.   {
  1863.     if (lpt->m_oldCursor)
  1864.       m_canvas->SetCursor(* lpt->m_oldCursor);
  1865.  
  1866. //    lpt->m_xpos = x; lpt->m_ypos = y;
  1867.  
  1868.     if (lineShape->GetTo())
  1869.     {
  1870.       lineShape->GetTo()->MoveLineToNewAttachment(dc, lineShape, x, y);
  1871.     }
  1872.   }
  1873.  
  1874.   // Needed?
  1875. #if 0
  1876.   int i = 0;
  1877.   for (i = 0; i < lineShape->GetLineControlPoints()->Number(); i++)
  1878.     if (((wxRealPoint *)(lineShape->GetLineControlPoints()->Nth(i)->Data())) == lpt->m_point)
  1879.       break;
  1880.  
  1881.   // N.B. in OnMoveControlPoint, an event handler in Hardy could have deselected
  1882.   // the line and therefore deleted 'this'. -> GPF, intermittently.
  1883.   // So assume at this point that we've been blown away.
  1884.  
  1885.   lineShape->OnMoveControlPoint(i+1, x, y);
  1886. #endif
  1887. }
  1888.  
  1889. // This is called only when a non-end control point is moved.
  1890. bool wxLineShape::OnMoveMiddleControlPoint(wxDC& dc, wxLineControlPoint* lpt, const wxRealPoint& pt)
  1891. {
  1892.     lpt->m_xpos = pt.x; lpt->m_ypos = pt.y;
  1893.     lpt->m_point->x = pt.x; lpt->m_point->y = pt.y;
  1894.  
  1895.     GetEventHandler()->OnMoveLink(dc);
  1896.  
  1897.     return TRUE;
  1898. }
  1899.  
  1900. // Implement movement of endpoint to a new attachment
  1901. // OBSOLETE: done by dragging with the left button.
  1902.  
  1903. #if 0
  1904. void wxLineControlPoint::OnDragRight(bool draw, double x, double y, int keys, int attachment)
  1905. {
  1906.   if (m_type == CONTROL_POINT_ENDPOINT_FROM || m_type == CONTROL_POINT_ENDPOINT_TO)
  1907.   {
  1908.     m_xpos = x; m_ypos = y;
  1909.   }
  1910. }
  1911.  
  1912. void wxLineControlPoint::OnBeginDragRight(double x, double y, int keys, int attachment)
  1913. {
  1914.   wxClientDC dc(GetCanvas());
  1915.   GetCanvas()->PrepareDC(dc);
  1916.  
  1917.   wxLineShape *lineShape = (wxLineShape *)m_shape;
  1918.   if (m_type == CONTROL_POINT_ENDPOINT_FROM || m_type == CONTROL_POINT_ENDPOINT_TO)
  1919.   {
  1920.     Erase(dc);
  1921.     lineShape->GetEventHandler()->OnDraw(dc);
  1922.     if (m_type == CONTROL_POINT_ENDPOINT_FROM)
  1923.     {
  1924.       lineShape->GetFrom()->GetEventHandler()->OnDraw(dc);
  1925.       lineShape->GetFrom()->GetEventHandler()->OnDrawContents(dc);
  1926.     }
  1927.     else
  1928.     {
  1929.       lineShape->GetTo()->GetEventHandler()->OnDraw(dc);
  1930.       lineShape->GetTo()->GetEventHandler()->OnDrawContents(dc);
  1931.     }
  1932.     m_canvas->SetCursor(wxCursor(wxCURSOR_BULLSEYE));
  1933.     m_oldCursor = wxSTANDARD_CURSOR;
  1934.   }
  1935. }
  1936.  
  1937. void wxLineControlPoint::OnEndDragRight(double x, double y, int keys, int attachment)
  1938. {
  1939.   wxClientDC dc(GetCanvas());
  1940.   GetCanvas()->PrepareDC(dc);
  1941.  
  1942.   wxLineShape *lineShape = (wxLineShape *)m_shape;
  1943.   if (m_type == CONTROL_POINT_ENDPOINT_FROM)
  1944.   {
  1945.     if (m_oldCursor)
  1946.       m_canvas->SetCursor(m_oldCursor);
  1947.  
  1948.     m_xpos = x; m_ypos = y;
  1949.  
  1950.     if (lineShape->GetFrom())
  1951.     {
  1952.       lineShape->GetFrom()->EraseLinks(dc);
  1953.  
  1954.       int new_attachment;
  1955.       double distance;
  1956.  
  1957.       if (lineShape->GetFrom()->HitTest(x, y, &new_attachment, &distance))
  1958.         lineShape->SetAttachments(new_attachment, lineShape->GetAttachmentTo());
  1959.  
  1960.       lineShape->GetFrom()->MoveLinks(dc);
  1961.     }
  1962.   }
  1963.   if (m_type == CONTROL_POINT_ENDPOINT_TO)
  1964.   {
  1965.     if (m_oldCursor)
  1966.       m_canvas->SetCursor(m_oldCursor);
  1967.     m_shape->Erase(dc);
  1968.  
  1969.     m_xpos = x; m_ypos = y;
  1970.  
  1971.     if (lineShape->GetTo())
  1972.     {
  1973.       lineShape->GetTo()->EraseLinks(dc);
  1974.  
  1975.       int new_attachment;
  1976.       double distance;
  1977.       if (lineShape->GetTo()->HitTest(x, y, &new_attachment, &distance))
  1978.         lineShape->SetAttachments(lineShape->GetAttachmentFrom(), new_attachment);
  1979.  
  1980.       lineShape->GetTo()->MoveLinks(dc);
  1981.     }
  1982.   }
  1983.   int i = 0;
  1984.   for (i = 0; i < lineShape->GetLineControlPoints()->Number(); i++)
  1985.     if (((wxRealPoint *)(lineShape->GetLineControlPoints()->Nth(i)->Data())) == m_point)
  1986.       break;
  1987.   lineShape->OnMoveControlPoint(i+1, x, y);
  1988.   if (!m_canvas->GetQuickEditMode()) m_canvas->Redraw(dc);
  1989. }
  1990. #endif
  1991.  
  1992. /*
  1993.  * Get the point on the given line (x1, y1) (x2, y2)
  1994.  * distance 'length' along from the end,
  1995.  * returned values in x and y
  1996.  */
  1997.  
  1998. void GetPointOnLine(double x1, double y1, double x2, double y2,
  1999.                     double length, double *x, double *y)
  2000. {
  2001.   double l = (double)sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1));
  2002.  
  2003.   if (l < 0.01)
  2004.     l = (double) 0.01;
  2005.  
  2006.   double i_bar = (x2 - x1)/l;
  2007.   double j_bar = (y2 - y1)/l;
  2008.  
  2009.   *x = (- length*i_bar) + x2;
  2010.   *y = (- length*j_bar) + y2;
  2011. }
  2012.  
  2013. wxArrowHead *wxLineShape::AddArrow(WXTYPE type, int end, double size, double xOffset,
  2014.     const wxString& name, wxPseudoMetaFile *mf, long arrowId)
  2015. {
  2016.   wxArrowHead *arrow = new wxArrowHead(type, end, size, xOffset, name, mf, arrowId);
  2017.   m_arcArrows.Append(arrow);
  2018.   return arrow;
  2019. }
  2020.  
  2021. /*
  2022.  * Add arrowhead at a particular position in the arrowhead list.
  2023.  */
  2024. bool wxLineShape::AddArrowOrdered(wxArrowHead *arrow, wxList& referenceList, int end)
  2025. {
  2026.   wxNode *refNode = referenceList.First();
  2027.   wxNode *currNode = m_arcArrows.First();
  2028.   wxString targetName(arrow->GetName());
  2029.   if (!refNode) return FALSE;
  2030.  
  2031.   // First check whether we need to insert in front of list,
  2032.   // because this arrowhead is the first in the reference
  2033.   // list and should therefore be first in the current list.
  2034.   wxArrowHead *refArrow = (wxArrowHead *)refNode->Data();
  2035.   if (refArrow->GetName() == targetName)
  2036.   {
  2037.     m_arcArrows.Insert(arrow);
  2038.     return TRUE;
  2039.   }
  2040.  
  2041.   while (refNode && currNode)
  2042.   {
  2043.     wxArrowHead *currArrow = (wxArrowHead *)currNode->Data();
  2044.     refArrow = (wxArrowHead *)refNode->Data();
  2045.  
  2046.     // Matching: advance current arrow pointer
  2047.     if ((currArrow->GetArrowEnd() == end) &&
  2048.         (currArrow->GetName() == refArrow->GetName()))
  2049.     {
  2050.       currNode = currNode->Next(); // Could be NULL now
  2051.       if (currNode)
  2052.         currArrow = (wxArrowHead *)currNode->Data();
  2053.     }
  2054.  
  2055.     // Check if we're at the correct position in the
  2056.     // reference list
  2057.     if (targetName == refArrow->GetName())
  2058.     {
  2059.       if (currNode)
  2060.         m_arcArrows.Insert(currNode, arrow);
  2061.       else
  2062.         m_arcArrows.Append(arrow);
  2063.       return TRUE;
  2064.     }
  2065.     refNode = refNode->Next();
  2066.   }
  2067.   m_arcArrows.Append(arrow);
  2068.   return TRUE;
  2069. }
  2070.  
  2071. void wxLineShape::ClearArrowsAtPosition(int end)
  2072. {
  2073.   wxNode *node = m_arcArrows.First();
  2074.   while (node)
  2075.   {
  2076.     wxArrowHead *arrow = (wxArrowHead *)node->Data();
  2077.     wxNode *next = node->Next();
  2078.     switch (end)
  2079.     {
  2080.       case -1:
  2081.       {
  2082.         delete arrow;
  2083.         delete node;
  2084.         break;
  2085.       }
  2086.       case ARROW_POSITION_START:
  2087.       {
  2088.         if (arrow->GetArrowEnd() == ARROW_POSITION_START)
  2089.         {
  2090.           delete arrow;
  2091.           delete node;
  2092.         }
  2093.         break;
  2094.       }
  2095.       case ARROW_POSITION_END:
  2096.       {
  2097.         if (arrow->GetArrowEnd() == ARROW_POSITION_END)
  2098.         {
  2099.           delete arrow;
  2100.           delete node;
  2101.         }
  2102.         break;
  2103.       }
  2104.       case ARROW_POSITION_MIDDLE:
  2105.       {
  2106.         if (arrow->GetArrowEnd() == ARROW_POSITION_MIDDLE)
  2107.         {
  2108.           delete arrow;
  2109.           delete node;
  2110.         }
  2111.         break;
  2112.       }
  2113.     }
  2114.     node = next;
  2115.   }
  2116. }
  2117.  
  2118. bool wxLineShape::ClearArrow(const wxString& name)
  2119. {
  2120.   wxNode *node = m_arcArrows.First();
  2121.   while (node)
  2122.   {
  2123.     wxArrowHead *arrow = (wxArrowHead *)node->Data();
  2124.     if (arrow->GetName() == name)
  2125.     {
  2126.       delete arrow;
  2127.       delete node;
  2128.       return TRUE;
  2129.     }
  2130.     node = node->Next();
  2131.   }
  2132.   return FALSE;
  2133. }
  2134.  
  2135. /*
  2136.  * Finds an arrowhead at the given position (if -1, any position)
  2137.  *
  2138.  */
  2139.  
  2140. wxArrowHead *wxLineShape::FindArrowHead(int position, const wxString& name)
  2141. {
  2142.   wxNode *node = m_arcArrows.First();
  2143.   while (node)
  2144.   {
  2145.     wxArrowHead *arrow = (wxArrowHead *)node->Data();
  2146.     if (((position == -1) || (position == arrow->GetArrowEnd())) &&
  2147.         (arrow->GetName() == name))
  2148.       return arrow;
  2149.     node = node->Next();
  2150.   }
  2151.   return NULL;
  2152. }
  2153.  
  2154. wxArrowHead *wxLineShape::FindArrowHead(long arrowId)
  2155. {
  2156.   wxNode *node = m_arcArrows.First();
  2157.   while (node)
  2158.   {
  2159.     wxArrowHead *arrow = (wxArrowHead *)node->Data();
  2160.     if (arrowId == arrow->GetId())
  2161.       return arrow;
  2162.     node = node->Next();
  2163.   }
  2164.   return NULL;
  2165. }
  2166.  
  2167. /*
  2168.  * Deletes an arrowhead at the given position (if -1, any position)
  2169.  *
  2170.  */
  2171.  
  2172. bool wxLineShape::DeleteArrowHead(int position, const wxString& name)
  2173. {
  2174.   wxNode *node = m_arcArrows.First();
  2175.   while (node)
  2176.   {
  2177.     wxArrowHead *arrow = (wxArrowHead *)node->Data();
  2178.     if (((position == -1) || (position == arrow->GetArrowEnd())) &&
  2179.         (arrow->GetName() == name))
  2180.     {
  2181.       delete arrow;
  2182.       delete node;
  2183.       return TRUE;
  2184.     }
  2185.     node = node->Next();
  2186.   }
  2187.   return FALSE;
  2188. }
  2189.  
  2190. // Overloaded DeleteArrowHead: pass arrowhead id.
  2191. bool wxLineShape::DeleteArrowHead(long id)
  2192. {
  2193.   wxNode *node = m_arcArrows.First();
  2194.   while (node)
  2195.   {
  2196.     wxArrowHead *arrow = (wxArrowHead *)node->Data();
  2197.     if (arrow->GetId() == id)
  2198.     {
  2199.       delete arrow;
  2200.       delete node;
  2201.       return TRUE;
  2202.     }
  2203.     node = node->Next();
  2204.   }
  2205.   return FALSE;
  2206. }
  2207.  
  2208. /*
  2209.  * Calculate the minimum width a line
  2210.  * occupies, for the purposes of drawing lines in tools.
  2211.  *
  2212.  */
  2213.  
  2214. double wxLineShape::FindMinimumWidth()
  2215. {
  2216.   double minWidth = 0.0;
  2217.   wxNode *node = m_arcArrows.First();
  2218.   while (node)
  2219.   {
  2220.     wxArrowHead *arrowHead = (wxArrowHead *)node->Data();
  2221.     minWidth += arrowHead->GetSize();
  2222.     if (node->Next())
  2223.       minWidth += arrowHead->GetSpacing();
  2224.  
  2225.     node = node->Next();
  2226.   }
  2227.   // We have ABSOLUTE minimum now. So
  2228.   // scale it to give it reasonable aesthetics
  2229.   // when drawing with line.
  2230.   if (minWidth > 0.0)
  2231.     minWidth = (double)(minWidth * 1.4);
  2232.   else
  2233.     minWidth = 20.0;
  2234.  
  2235.   SetEnds(0.0, 0.0, minWidth, 0.0);
  2236.   Initialise();
  2237.  
  2238.   return minWidth;
  2239. }
  2240.  
  2241. // Find which position we're talking about at this (x, y).
  2242. // Returns ARROW_POSITION_START, ARROW_POSITION_MIDDLE, ARROW_POSITION_END
  2243. int wxLineShape::FindLinePosition(double x, double y)
  2244. {
  2245.   double startX, startY, endX, endY;
  2246.   GetEnds(&startX, &startY, &endX, &endY);
  2247.  
  2248.   // Find distances from centre, start and end. The smallest wins.
  2249.   double centreDistance = (double)(sqrt((x - m_xpos)*(x - m_xpos) + (y - m_ypos)*(y - m_ypos)));
  2250.   double startDistance = (double)(sqrt((x - startX)*(x - startX) + (y - startY)*(y - startY)));
  2251.   double endDistance = (double)(sqrt((x - endX)*(x - endX) + (y - endY)*(y - endY)));
  2252.  
  2253.   if (centreDistance < startDistance && centreDistance < endDistance)
  2254.     return ARROW_POSITION_MIDDLE;
  2255.   else if (startDistance < endDistance)
  2256.     return ARROW_POSITION_START;
  2257.   else
  2258.     return ARROW_POSITION_END;
  2259. }
  2260.  
  2261. // Set alignment flags
  2262. void wxLineShape::SetAlignmentOrientation(bool isEnd, bool isHoriz)
  2263. {
  2264.   if (isEnd)
  2265.   {
  2266.     if (isHoriz && ((m_alignmentEnd & LINE_ALIGNMENT_HORIZ) != LINE_ALIGNMENT_HORIZ))
  2267.       m_alignmentEnd |= LINE_ALIGNMENT_HORIZ;
  2268.     else if (!isHoriz && ((m_alignmentEnd & LINE_ALIGNMENT_HORIZ) == LINE_ALIGNMENT_HORIZ))
  2269.       m_alignmentEnd -= LINE_ALIGNMENT_HORIZ;
  2270.   }
  2271.   else
  2272.   {
  2273.     if (isHoriz && ((m_alignmentStart & LINE_ALIGNMENT_HORIZ) != LINE_ALIGNMENT_HORIZ))
  2274.       m_alignmentStart |= LINE_ALIGNMENT_HORIZ;
  2275.     else if (!isHoriz && ((m_alignmentStart & LINE_ALIGNMENT_HORIZ) == LINE_ALIGNMENT_HORIZ))
  2276.       m_alignmentStart -= LINE_ALIGNMENT_HORIZ;
  2277.   }
  2278. }
  2279.  
  2280. void wxLineShape::SetAlignmentType(bool isEnd, int alignType)
  2281. {
  2282.   if (isEnd)
  2283.   {
  2284.     if (alignType == LINE_ALIGNMENT_TO_NEXT_HANDLE)
  2285.     {
  2286.       if ((m_alignmentEnd & LINE_ALIGNMENT_TO_NEXT_HANDLE) != LINE_ALIGNMENT_TO_NEXT_HANDLE)
  2287.         m_alignmentEnd |= LINE_ALIGNMENT_TO_NEXT_HANDLE;
  2288.     }
  2289.     else if ((m_alignmentEnd & LINE_ALIGNMENT_TO_NEXT_HANDLE) == LINE_ALIGNMENT_TO_NEXT_HANDLE)
  2290.       m_alignmentEnd -= LINE_ALIGNMENT_TO_NEXT_HANDLE;
  2291.   }
  2292.   else
  2293.   {
  2294.     if (alignType == LINE_ALIGNMENT_TO_NEXT_HANDLE)
  2295.     {
  2296.       if ((m_alignmentStart & LINE_ALIGNMENT_TO_NEXT_HANDLE) != LINE_ALIGNMENT_TO_NEXT_HANDLE)
  2297.         m_alignmentStart |= LINE_ALIGNMENT_TO_NEXT_HANDLE;
  2298.     }
  2299.     else if ((m_alignmentStart & LINE_ALIGNMENT_TO_NEXT_HANDLE) == LINE_ALIGNMENT_TO_NEXT_HANDLE)
  2300.       m_alignmentStart -= LINE_ALIGNMENT_TO_NEXT_HANDLE;
  2301.   }
  2302. }
  2303.  
  2304. bool wxLineShape::GetAlignmentOrientation(bool isEnd)
  2305. {
  2306.   if (isEnd)
  2307.     return ((m_alignmentEnd & LINE_ALIGNMENT_HORIZ) == LINE_ALIGNMENT_HORIZ);
  2308.   else
  2309.     return ((m_alignmentStart & LINE_ALIGNMENT_HORIZ) == LINE_ALIGNMENT_HORIZ);
  2310. }
  2311.  
  2312. int wxLineShape::GetAlignmentType(bool isEnd)
  2313. {
  2314.   if (isEnd)
  2315.     return (m_alignmentEnd & LINE_ALIGNMENT_TO_NEXT_HANDLE);
  2316.   else
  2317.     return (m_alignmentStart & LINE_ALIGNMENT_TO_NEXT_HANDLE);
  2318. }
  2319.  
  2320. wxRealPoint *wxLineShape::GetNextControlPoint(wxShape *nodeObject)
  2321. {
  2322.   int n = m_lineControlPoints->Number();
  2323.   int nn = 0;
  2324.   if (m_to == nodeObject)
  2325.   {
  2326.     // Must be END of line, so we want (n - 1)th control point.
  2327.     // But indexing ends at n-1, so subtract 2.
  2328.     nn = n - 2;
  2329.   }
  2330.   else nn = 1;
  2331.   wxNode *node = m_lineControlPoints->Nth(nn);
  2332.   if (node)
  2333.   {
  2334.     return (wxRealPoint *)node->Data();
  2335.   }
  2336.   else
  2337.     return FALSE;
  2338. }
  2339.  
  2340. /*
  2341.  * Arrowhead
  2342.  *
  2343.  */
  2344.  
  2345. IMPLEMENT_DYNAMIC_CLASS(wxArrowHead, wxObject)
  2346.  
  2347. wxArrowHead::wxArrowHead(WXTYPE type, int end, double size, double dist, const wxString& name,
  2348.                      wxPseudoMetaFile *mf, long arrowId)
  2349. {
  2350.   m_arrowType = type; m_arrowEnd = end; m_arrowSize = size;
  2351.   m_xOffset = dist;
  2352.   m_yOffset = 0.0;
  2353.   m_spacing = 5.0;
  2354.  
  2355.   m_arrowName = name;
  2356.   m_metaFile = mf;
  2357.   m_id = arrowId;
  2358.   if (m_id == -1)
  2359.     m_id = wxNewId();
  2360. }
  2361.  
  2362. wxArrowHead::wxArrowHead(wxArrowHead& toCopy)
  2363. {
  2364.   m_arrowType = toCopy.m_arrowType; m_arrowEnd = toCopy.GetArrowEnd();
  2365.   m_arrowSize = toCopy.m_arrowSize;
  2366.   m_xOffset = toCopy.m_xOffset;
  2367.   m_yOffset = toCopy.m_yOffset;
  2368.   m_spacing = toCopy.m_spacing;
  2369.   m_arrowName = toCopy.m_arrowName ;
  2370.   if (toCopy.m_metaFile)
  2371.     m_metaFile = new wxPseudoMetaFile(*(toCopy.m_metaFile));
  2372.   else
  2373.     m_metaFile = NULL;
  2374.   m_id = wxNewId();
  2375. }
  2376.  
  2377. wxArrowHead::~wxArrowHead()
  2378. {
  2379.   if (m_metaFile) delete m_metaFile;
  2380. }
  2381.  
  2382. void wxArrowHead::SetSize(double size)
  2383. {
  2384.   m_arrowSize = size;
  2385.   if ((m_arrowType == ARROW_METAFILE) && m_metaFile)
  2386.   {
  2387.     double oldWidth = m_metaFile->m_width;
  2388.     if (oldWidth == 0.0)
  2389.       return;
  2390.  
  2391.     double scale = (double)(size/oldWidth);
  2392.     if (scale != 1.0)
  2393.       m_metaFile->Scale(scale, scale);
  2394.   }
  2395. }
  2396.  
  2397. // Can override this to create a different class of label shape
  2398. wxLabelShape* wxLineShape::OnCreateLabelShape(wxLineShape *parent, wxShapeRegion *region, double w, double h)
  2399. {
  2400.     return new wxLabelShape(parent, region, w, h);
  2401. }
  2402.  
  2403. /*
  2404.  * Label object
  2405.  *
  2406.  */
  2407.  
  2408. IMPLEMENT_DYNAMIC_CLASS(wxLabelShape, wxRectangleShape)
  2409.  
  2410. wxLabelShape::wxLabelShape(wxLineShape *parent, wxShapeRegion *region, double w, double h):wxRectangleShape(w, h)
  2411. {
  2412.   m_lineShape = parent;
  2413.   m_shapeRegion = region;
  2414.   SetPen(wxThePenList->FindOrCreatePen(wxColour(0, 0, 0), 1, wxDOT));
  2415. }
  2416.  
  2417. wxLabelShape::~wxLabelShape()
  2418. {
  2419. }
  2420.  
  2421. void wxLabelShape::OnDraw(wxDC& dc)
  2422. {
  2423.   if (m_lineShape && !m_lineShape->GetDrawHandles())
  2424.     return;
  2425.  
  2426.     double x1 = (double)(m_xpos - m_width/2.0);
  2427.     double y1 = (double)(m_ypos - m_height/2.0);
  2428.  
  2429.     if (m_pen)
  2430.     {
  2431.       if (m_pen->GetWidth() == 0)
  2432.         dc.SetPen(* g_oglTransparentPen);
  2433.       else
  2434.         dc.SetPen(* m_pen);
  2435.     }
  2436.     dc.SetBrush(* wxTRANSPARENT_BRUSH);
  2437.  
  2438.     if (m_cornerRadius > 0.0)
  2439.       dc.DrawRoundedRectangle(WXROUND(x1), WXROUND(y1), WXROUND(m_width), WXROUND(m_height), m_cornerRadius);
  2440.     else
  2441.       dc.DrawRectangle(WXROUND(x1), WXROUND(y1), WXROUND(m_width), WXROUND(m_height));
  2442. }
  2443.  
  2444. void wxLabelShape::OnDrawContents(wxDC& dc)
  2445. {
  2446. }
  2447.  
  2448. void wxLabelShape::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
  2449. {
  2450.   wxRectangleShape::OnDragLeft(draw, x, y, keys, attachment);
  2451. }
  2452.  
  2453. void wxLabelShape::OnBeginDragLeft(double x, double y, int keys, int attachment)
  2454. {
  2455.   wxRectangleShape::OnBeginDragLeft(x, y, keys, attachment);
  2456. }
  2457.  
  2458. void wxLabelShape::OnEndDragLeft(double x, double y, int keys, int attachment)
  2459. {
  2460.   wxRectangleShape::OnEndDragLeft(x, y, keys, attachment);
  2461. }
  2462.  
  2463. bool wxLabelShape::OnMovePre(wxDC& dc, double x, double y, double old_x, double old_y, bool display)
  2464. {
  2465.     return m_lineShape->OnLabelMovePre(dc, this, x, y, old_x, old_y, display);
  2466. }
  2467.  
  2468. bool wxLineShape::OnLabelMovePre(wxDC& dc, wxLabelShape* labelShape, double x, double y, double old_x, double old_y, bool display)
  2469. {
  2470.   labelShape->m_shapeRegion->SetSize(labelShape->GetWidth(), labelShape->GetHeight());
  2471.  
  2472.   // Find position in line's region list
  2473.   int i = 0;
  2474.   wxNode *node = GetRegions().First();
  2475.   while (node)
  2476.   {
  2477.     if (labelShape->m_shapeRegion == (wxShapeRegion *)node->Data())
  2478.       node = NULL;
  2479.     else
  2480.     {
  2481.       node = node->Next();
  2482.       i ++;
  2483.     }
  2484.   }
  2485.   double xx, yy;
  2486.   GetLabelPosition(i, &xx, &yy);
  2487.   // Set the region's offset, relative to the default position for
  2488.   // each region.
  2489.   labelShape->m_shapeRegion->SetPosition((double)(x - xx), (double)(y - yy));
  2490.  
  2491.   labelShape->SetX(x);
  2492.   labelShape->SetY(y);
  2493.  
  2494.   // Need to reformat to fit region.
  2495.   if (labelShape->m_shapeRegion->GetText())
  2496.   {
  2497.  
  2498.     wxString s(labelShape->m_shapeRegion->GetText());
  2499.     labelShape->FormatText(dc, s, i);
  2500.     DrawRegion(dc, labelShape->m_shapeRegion, xx, yy);
  2501.   }
  2502.   return TRUE;
  2503. }
  2504.  
  2505. // Divert left and right clicks to line object
  2506. void wxLabelShape::OnLeftClick(double x, double y, int keys, int attachment)
  2507. {
  2508.   m_lineShape->GetEventHandler()->OnLeftClick(x, y, keys, attachment);
  2509. }
  2510.  
  2511. void wxLabelShape::OnRightClick(double x, double y, int keys, int attachment)
  2512. {
  2513.   m_lineShape->GetEventHandler()->OnRightClick(x, y, keys, attachment);
  2514. }
  2515.  
  2516.