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