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 / basic2.cpp < prev    next >
C/C++ Source or Header  |  2002-12-28  |  54KB  |  1,901 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        basic2.cpp
  3. // Purpose:     Basic OGL classes (2)
  4. // Author:      Julian Smart
  5. // Modified by:
  6. // Created:     12/07/98
  7. // RCS-ID:      $Id: basic2.cpp,v 1.4.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 "basicp.h"
  14. #endif
  15.  
  16. // For compilers that support precompilation, includes "wx.h".
  17. #include "wx/wxprec.h"
  18.  
  19. #ifdef __BORLANDC__
  20. #pragma hdrstop
  21. #endif
  22.  
  23. #ifndef WX_PRECOMP
  24. #include <wx/wx.h>
  25. #endif
  26.  
  27. #include <wx/wxexpr.h>
  28.  
  29. #ifdef new
  30. #undef new
  31. #endif
  32.  
  33. #include <stdio.h>
  34. #include <ctype.h>
  35. #include <math.h>
  36.  
  37. #include <wx/ogl/basic.h>
  38. #include <wx/ogl/basicp.h>
  39. #include <wx/ogl/composit.h>
  40. #include <wx/ogl/lines.h>
  41. #include <wx/ogl/canvas.h>
  42. #include <wx/ogl/divided.h>
  43. #include <wx/ogl/misc.h>
  44.  
  45. // Control point types
  46. // Rectangle and most other shapes
  47. #define CONTROL_POINT_VERTICAL   1
  48. #define CONTROL_POINT_HORIZONTAL 2
  49. #define CONTROL_POINT_DIAGONAL   3
  50.  
  51. // Line
  52. #define CONTROL_POINT_ENDPOINT_TO 4
  53. #define CONTROL_POINT_ENDPOINT_FROM 5
  54. #define CONTROL_POINT_LINE       6
  55.  
  56. // Two stage construction: need to call Create
  57. IMPLEMENT_DYNAMIC_CLASS(wxPolygonShape, wxShape)
  58.  
  59. wxPolygonShape::wxPolygonShape()
  60. {
  61.   m_points = NULL;
  62.   m_originalPoints = NULL;
  63. }
  64.  
  65. void wxPolygonShape::Create(wxList *the_points)
  66. {
  67.   ClearPoints();
  68.  
  69.   m_originalPoints = the_points;
  70.  
  71.   // Duplicate the list of points
  72.   m_points = new wxList;
  73.  
  74.   wxNode *node = the_points->First();
  75.   while (node)
  76.   {
  77.     wxRealPoint *point = (wxRealPoint *)node->Data();
  78.     wxRealPoint *new_point = new wxRealPoint(point->x, point->y);
  79.     m_points->Append((wxObject*) new_point);
  80.     node = node->Next();
  81.   }
  82.   CalculateBoundingBox();
  83.   m_originalWidth = m_boundWidth;
  84.   m_originalHeight = m_boundHeight;
  85.   SetDefaultRegionSize();
  86. }
  87.  
  88. wxPolygonShape::~wxPolygonShape()
  89. {
  90.     ClearPoints();
  91. }
  92.  
  93. void wxPolygonShape::ClearPoints()
  94. {
  95.   if (m_points)
  96.   {
  97.     wxNode *node = m_points->First();
  98.     while (node)
  99.     {
  100.       wxRealPoint *point = (wxRealPoint *)node->Data();
  101.       delete point;
  102.       delete node;
  103.       node = m_points->First();
  104.     }
  105.     delete m_points;
  106.     m_points = NULL;
  107.   }
  108.   if (m_originalPoints)
  109.   {
  110.     wxNode *node = m_originalPoints->First();
  111.     while (node)
  112.     {
  113.       wxRealPoint *point = (wxRealPoint *)node->Data();
  114.       delete point;
  115.       delete node;
  116.       node = m_originalPoints->First();
  117.     }
  118.     delete m_originalPoints;
  119.     m_originalPoints = NULL;
  120.   }
  121. }
  122.  
  123.  
  124. // Width and height. Centre of object is centre of box.
  125. void wxPolygonShape::GetBoundingBoxMin(double *width, double *height)
  126. {
  127.   *width = m_boundWidth;
  128.   *height = m_boundHeight;
  129. }
  130.  
  131. void wxPolygonShape::CalculateBoundingBox()
  132. {
  133.   // Calculate bounding box at construction (and presumably resize) time
  134.   double left = 10000;
  135.   double right = -10000;
  136.   double top = 10000;
  137.   double bottom = -10000;
  138.  
  139.   wxNode *node = m_points->First();
  140.   while (node)
  141.   {
  142.     wxRealPoint *point = (wxRealPoint *)node->Data();
  143.     if (point->x < left) left = point->x;
  144.     if (point->x > right) right = point->x;
  145.  
  146.     if (point->y < top) top = point->y;
  147.     if (point->y > bottom) bottom = point->y;
  148.  
  149.     node = node->Next();
  150.   }
  151.   m_boundWidth = right - left;
  152.   m_boundHeight = bottom - top;
  153. }
  154.  
  155. // Recalculates the centre of the polygon, and
  156. // readjusts the point offsets accordingly.
  157. // Necessary since the centre of the polygon
  158. // is expected to be the real centre of the bounding
  159. // box.
  160. void wxPolygonShape::CalculatePolygonCentre()
  161. {
  162.   double left = 10000;
  163.   double right = -10000;
  164.   double top = 10000;
  165.   double bottom = -10000;
  166.  
  167.   wxNode *node = m_points->First();
  168.   while (node)
  169.   {
  170.     wxRealPoint *point = (wxRealPoint *)node->Data();
  171.     if (point->x < left) left = point->x;
  172.     if (point->x > right) right = point->x;
  173.  
  174.     if (point->y < top) top = point->y;
  175.     if (point->y > bottom) bottom = point->y;
  176.  
  177.     node = node->Next();
  178.   }
  179.   double bwidth = right - left;
  180.   double bheight = bottom - top;
  181.  
  182.   double newCentreX = (double)(left + (bwidth/2.0));
  183.   double newCentreY = (double)(top + (bheight/2.0));
  184.  
  185.   node = m_points->First();
  186.   while (node)
  187.   {
  188.     wxRealPoint *point = (wxRealPoint *)node->Data();
  189.     point->x -= newCentreX;
  190.     point->y -= newCentreY;
  191.     node = node->Next();
  192.   }
  193.   m_xpos += newCentreX;
  194.   m_ypos += newCentreY;
  195. }
  196.  
  197. bool PolylineHitTest(double n, double xvec[], double yvec[],
  198.                            double x1, double y1, double x2, double y2)
  199. {
  200.   bool isAHit = FALSE;
  201.   int i;
  202.   double lastx = xvec[0];
  203.   double lasty = yvec[0];
  204.  
  205.   double min_ratio = 1.0;
  206.   double line_ratio;
  207.   double other_ratio;
  208.  
  209. //  char buf[300];
  210.   for (i = 1; i < n; i++)
  211.   {
  212.     oglCheckLineIntersection(x1, y1, x2, y2, lastx, lasty, xvec[i], yvec[i],
  213.                             &line_ratio, &other_ratio);
  214.     if (line_ratio != 1.0)
  215.       isAHit = TRUE;
  216. //    sprintf(buf, "Line ratio = %.2f, other ratio = %.2f\n", line_ratio, other_ratio);
  217. //    ClipsErrorFunction(buf);
  218.     lastx = xvec[i];
  219.     lasty = yvec[i];
  220.  
  221.     if (line_ratio < min_ratio)
  222.       min_ratio = line_ratio;
  223.   }
  224.  
  225.   // Do last (implicit) line if last and first doubles are not identical
  226.   if (!(xvec[0] == lastx && yvec[0] == lasty))
  227.   {
  228.     oglCheckLineIntersection(x1, y1, x2, y2, lastx, lasty, xvec[0], yvec[0],
  229.                             &line_ratio, &other_ratio);
  230.     if (line_ratio != 1.0)
  231.       isAHit = TRUE;
  232. //    sprintf(buf, "Line ratio = %.2f, other ratio = %.2f\n", line_ratio, other_ratio);
  233. //    ClipsErrorFunction(buf);
  234.  
  235.     if (line_ratio < min_ratio)
  236.       min_ratio = line_ratio;
  237.   }
  238. //  ClipsErrorFunction("\n");
  239.   return isAHit;
  240. }
  241.  
  242. bool wxPolygonShape::HitTest(double x, double y, int *attachment, double *distance)
  243. {
  244.   // Imagine four lines radiating from this point. If all of these lines hit the polygon,
  245.   // we're inside it, otherwise we're not. Obviously we'd need more radiating lines
  246.   // to be sure of correct results for very strange (concave) shapes.
  247.   double endPointsX[4];
  248.   double endPointsY[4];
  249.   // North
  250.   endPointsX[0] = x;
  251.   endPointsY[0] = (double)(y - 1000.0);
  252.   // East
  253.   endPointsX[1] = (double)(x + 1000.0);
  254.   endPointsY[1] = y;
  255.   // South
  256.   endPointsX[2] = x;
  257.   endPointsY[2] = (double)(y + 1000.0);
  258.   // West
  259.   endPointsX[3] = (double)(x - 1000.0);
  260.   endPointsY[3] = y;
  261.  
  262.   // Store polygon points in an array
  263.   int np = m_points->Number();
  264.   double *xpoints = new double[np];
  265.   double *ypoints = new double[np];
  266.   wxNode *node = m_points->First();
  267.   int i = 0;
  268.   while (node)
  269.   {
  270.     wxRealPoint *point = (wxRealPoint *)node->Data();
  271.     xpoints[i] = point->x + m_xpos;
  272.     ypoints[i] = point->y + m_ypos;
  273.     node = node->Next();
  274.     i ++;
  275.   }
  276.  
  277.   // We assume it's inside the polygon UNLESS one or more
  278.   // lines don't hit the outline.
  279.   bool isContained = TRUE;
  280.  
  281.   int noPoints = 4;
  282.   for (i = 0; i < noPoints; i++)
  283.   {
  284.     if (!PolylineHitTest(np, xpoints, ypoints, x, y, endPointsX[i], endPointsY[i]))
  285.       isContained = FALSE;
  286.   }
  287. /*
  288.   if (isContained)
  289.     ClipsErrorFunction("It's a hit!\n");
  290.   else
  291.     ClipsErrorFunction("No hit.\n");
  292. */
  293.   delete[] xpoints;
  294.   delete[] ypoints;
  295.  
  296.   if (!isContained)
  297.     return FALSE;
  298.  
  299.   int nearest_attachment = 0;
  300.  
  301.   // If a hit, check the attachment points within the object.
  302.   int n = GetNumberOfAttachments();
  303.   double nearest = 999999.0;
  304.  
  305.   for (i = 0; i < n; i++)
  306.   {
  307.     double xp, yp;
  308.     if (GetAttachmentPositionEdge(i, &xp, &yp))
  309.     {
  310.       double l = (double)sqrt(((xp - x) * (xp - x)) +
  311.                  ((yp - y) * (yp - y)));
  312.       if (l < nearest)
  313.       {
  314.         nearest = l;
  315.         nearest_attachment = i;
  316.       }
  317.     }
  318.   }
  319.   *attachment = nearest_attachment;
  320.   *distance = nearest;
  321.   return TRUE;
  322. }
  323.  
  324. // Really need to be able to reset the shape! Otherwise, if the
  325. // points ever go to zero, we've lost it, and can't resize.
  326. void wxPolygonShape::SetSize(double new_width, double new_height, bool recursive)
  327. {
  328.   SetAttachmentSize(new_width, new_height);
  329.  
  330.   // Multiply all points by proportion of new size to old size
  331.   double x_proportion = (double)(fabs(new_width/m_originalWidth));
  332.   double y_proportion = (double)(fabs(new_height/m_originalHeight));
  333.  
  334.   wxNode *node = m_points->First();
  335.   wxNode *original_node = m_originalPoints->First();
  336.   while (node && original_node)
  337.   {
  338.     wxRealPoint *point = (wxRealPoint *)node->Data();
  339.     wxRealPoint *original_point = (wxRealPoint *)original_node->Data();
  340.  
  341.     point->x = (original_point->x * x_proportion);
  342.     point->y = (original_point->y * y_proportion);
  343.  
  344.     node = node->Next();
  345.     original_node = original_node->Next();
  346.   }
  347.  
  348. //  CalculateBoundingBox();
  349.   m_boundWidth = (double)fabs(new_width);
  350.   m_boundHeight = (double)fabs(new_height);
  351.   SetDefaultRegionSize();
  352. }
  353.  
  354. // Make the original points the same as the working points
  355. void wxPolygonShape::UpdateOriginalPoints()
  356. {
  357.   if (!m_originalPoints) m_originalPoints = new wxList;
  358.   wxNode *original_node = m_originalPoints->First();
  359.   while (original_node)
  360.   {
  361.     wxNode *next_node = original_node->Next();
  362.     wxRealPoint *original_point = (wxRealPoint *)original_node->Data();
  363.     delete original_point;
  364.     delete original_node;
  365.  
  366.     original_node = next_node;
  367.   }
  368.  
  369.   wxNode *node = m_points->First();
  370.   while (node)
  371.   {
  372.     wxRealPoint *point = (wxRealPoint *)node->Data();
  373.     wxRealPoint *original_point = new wxRealPoint(point->x, point->y);
  374.     m_originalPoints->Append((wxObject*) original_point);
  375.  
  376.     node = node->Next();
  377.   }
  378.   CalculateBoundingBox();
  379.   m_originalWidth = m_boundWidth;
  380.   m_originalHeight = m_boundHeight;
  381. }
  382.  
  383. void wxPolygonShape::AddPolygonPoint(int pos)
  384. {
  385.   wxNode *node = m_points->Nth(pos);
  386.   if (!node) node = m_points->First();
  387.   wxRealPoint *firstPoint = (wxRealPoint *)node->Data();
  388.  
  389.   wxNode *node2 = m_points->Nth(pos + 1);
  390.   if (!node2) node2 = m_points->First();
  391.   wxRealPoint *secondPoint = (wxRealPoint *)node2->Data();
  392.  
  393.   double x = (double)((secondPoint->x - firstPoint->x)/2.0 + firstPoint->x);
  394.   double y = (double)((secondPoint->y - firstPoint->y)/2.0 + firstPoint->y);
  395.   wxRealPoint *point = new wxRealPoint(x, y);
  396.  
  397.   if (pos >= (m_points->Number() - 1))
  398.     m_points->Append((wxObject*) point);
  399.   else
  400.     m_points->Insert(node2, (wxObject*) point);
  401.  
  402.   UpdateOriginalPoints();
  403.  
  404.   if (m_selected)
  405.   {
  406.     DeleteControlPoints();
  407.     MakeControlPoints();
  408.   }
  409. }
  410.  
  411. void wxPolygonShape::DeletePolygonPoint(int pos)
  412. {
  413.   wxNode *node = m_points->Nth(pos);
  414.   if (node)
  415.   {
  416.     wxRealPoint *point = (wxRealPoint *)node->Data();
  417.     delete point;
  418.     delete node;
  419.     UpdateOriginalPoints();
  420.     if (m_selected)
  421.     {
  422.       DeleteControlPoints();
  423.       MakeControlPoints();
  424.     }
  425.   }
  426. }
  427.  
  428. // Assume (x1, y1) is centre of box (most generally, line end at box)
  429. bool wxPolygonShape::GetPerimeterPoint(double x1, double y1,
  430.                                      double x2, double y2,
  431.                                      double *x3, double *y3)
  432. {
  433.   int n = m_points->Number();
  434.  
  435.   // First check for situation where the line is vertical,
  436.   // and we would want to connect to a point on that vertical --
  437.   // oglFindEndForPolyline can't cope with this (the arrow
  438.   // gets drawn to the wrong place).
  439.   if ((m_attachmentMode == ATTACHMENT_MODE_NONE) && (x1 == x2))
  440.   {
  441.     // Look for the point we'd be connecting to. This is
  442.     // a heuristic...
  443.     wxNode *node = m_points->First();
  444.     while (node)
  445.     {
  446.       wxRealPoint *point = (wxRealPoint *)node->Data();
  447.       if (point->x == 0.0)
  448.       {
  449.         if ((y2 > y1) && (point->y > 0.0))
  450.         {
  451.           *x3 = point->x + m_xpos;
  452.           *y3 = point->y + m_ypos;
  453.           return TRUE;
  454.         }
  455.         else if ((y2 < y1) && (point->y < 0.0))
  456.         {
  457.           *x3 = point->x + m_xpos;
  458.           *y3 = point->y + m_ypos;
  459.           return TRUE;
  460.         }
  461.       }
  462.       node = node->Next();
  463.     }
  464.   }
  465.  
  466.   double *xpoints = new double[n];
  467.   double *ypoints = new double[n];
  468.  
  469.   wxNode *node = m_points->First();
  470.   int i = 0;
  471.   while (node)
  472.   {
  473.     wxRealPoint *point = (wxRealPoint *)node->Data();
  474.     xpoints[i] = point->x + m_xpos;
  475.     ypoints[i] = point->y + m_ypos;
  476.     node = node->Next();
  477.     i ++;
  478.   }
  479.  
  480.   oglFindEndForPolyline(n, xpoints, ypoints,
  481.                         x1, y1, x2, y2, x3, y3);
  482.  
  483.   delete[] xpoints;
  484.   delete[] ypoints;
  485.  
  486.   return TRUE;
  487. }
  488.  
  489. void wxPolygonShape::OnDraw(wxDC& dc)
  490. {
  491.     int n = m_points->Number();
  492.     wxPoint *intPoints = new wxPoint[n];
  493.     int i;
  494.     for (i = 0; i < n; i++)
  495.     {
  496.       wxRealPoint* point = (wxRealPoint*) m_points->Nth(i)->Data();
  497.       intPoints[i].x = WXROUND(point->x);
  498.       intPoints[i].y = WXROUND(point->y);
  499.     }
  500.  
  501.     if (m_shadowMode != SHADOW_NONE)
  502.     {
  503.       if (m_shadowBrush)
  504.         dc.SetBrush(* m_shadowBrush);
  505.       dc.SetPen(* g_oglTransparentPen);
  506.  
  507.       dc.DrawPolygon(n, intPoints, WXROUND(m_xpos + m_shadowOffsetX), WXROUND(m_ypos + m_shadowOffsetY));
  508.     }
  509.  
  510.     if (m_pen)
  511.     {
  512.       if (m_pen->GetWidth() == 0)
  513.         dc.SetPen(* g_oglTransparentPen);
  514.       else
  515.         dc.SetPen(* m_pen);
  516.     }
  517.     if (m_brush)
  518.       dc.SetBrush(* m_brush);
  519.     dc.DrawPolygon(n, intPoints, WXROUND(m_xpos), WXROUND(m_ypos));
  520.  
  521.     delete[] intPoints;
  522. }
  523.  
  524. void wxPolygonShape::OnDrawOutline(wxDC& dc, double x, double y, double w, double h)
  525. {
  526.   dc.SetBrush(* wxTRANSPARENT_BRUSH);
  527.   // Multiply all points by proportion of new size to old size
  528.   double x_proportion = (double)(fabs(w/m_originalWidth));
  529.   double y_proportion = (double)(fabs(h/m_originalHeight));
  530.  
  531.   int n = m_originalPoints->Number();
  532.   wxPoint *intPoints = new wxPoint[n];
  533.   int i;
  534.   for (i = 0; i < n; i++)
  535.   {
  536.     wxRealPoint* point = (wxRealPoint*) m_originalPoints->Nth(i)->Data();
  537.     intPoints[i].x = WXROUND(x_proportion * point->x);
  538.     intPoints[i].y = WXROUND(y_proportion * point->y);
  539.   }
  540.   dc.DrawPolygon(n, intPoints, WXROUND(x), WXROUND(y));
  541.   delete[] intPoints;
  542. }
  543.  
  544. // Make as many control points as there are vertices.
  545. void wxPolygonShape::MakeControlPoints()
  546. {
  547.   wxNode *node = m_points->First();
  548.   while (node)
  549.   {
  550.     wxRealPoint *point = (wxRealPoint *)node->Data();
  551.     wxPolygonControlPoint *control = new wxPolygonControlPoint(m_canvas, this, CONTROL_POINT_SIZE,
  552.       point, point->x, point->y);
  553.     m_canvas->AddShape(control);
  554.     m_controlPoints.Append(control);
  555.     node = node->Next();
  556.   }
  557. }
  558.  
  559. void wxPolygonShape::ResetControlPoints()
  560. {
  561.   wxNode *node = m_points->First();
  562.   wxNode *controlPointNode = m_controlPoints.First();
  563.   while (node && controlPointNode)
  564.   {
  565.     wxRealPoint *point = (wxRealPoint *)node->Data();
  566.     wxPolygonControlPoint *controlPoint = (wxPolygonControlPoint *)controlPointNode->Data();
  567.  
  568.     controlPoint->m_xoffset = point->x;
  569.     controlPoint->m_yoffset = point->y;
  570.     controlPoint->m_polygonVertex = point;
  571.  
  572.     node = node->Next();
  573.     controlPointNode = controlPointNode->Next();
  574.   }
  575. }
  576.  
  577.  
  578. #if wxUSE_PROLOGIO
  579. void wxPolygonShape::WriteAttributes(wxExpr *clause)
  580. {
  581.   wxShape::WriteAttributes(clause);
  582.  
  583.   clause->AddAttributeValue(wxT("x"), m_xpos);
  584.   clause->AddAttributeValue(wxT("y"), m_ypos);
  585.  
  586.   // Make a list of lists for the coordinates
  587.   wxExpr *list = new wxExpr(wxExprList);
  588.   wxNode *node = m_points->First();
  589.   while (node)
  590.   {
  591.     wxRealPoint *point = (wxRealPoint *)node->Data();
  592.     wxExpr *point_list = new wxExpr(wxExprList);
  593.     wxExpr *x_expr = new wxExpr((double)point->x);
  594.     wxExpr *y_expr = new wxExpr((double)point->y);
  595.  
  596.     point_list->Append(x_expr);
  597.     point_list->Append(y_expr);
  598.     list->Append(point_list);
  599.  
  600.     node = node->Next();
  601.   }
  602.   clause->AddAttributeValue(wxT("points"), list);
  603.  
  604.   // Save the original (unscaled) points
  605.   list = new wxExpr(wxExprList);
  606.   node = m_originalPoints->First();
  607.   while (node)
  608.   {
  609.     wxRealPoint *point = (wxRealPoint *)node->Data();
  610.     wxExpr *point_list = new wxExpr(wxExprList);
  611.     wxExpr *x_expr = new wxExpr((double) point->x);
  612.     wxExpr *y_expr = new wxExpr((double) point->y);
  613.     point_list->Append(x_expr);
  614.     point_list->Append(y_expr);
  615.     list->Append(point_list);
  616.  
  617.     node = node->Next();
  618.   }
  619.   clause->AddAttributeValue(wxT("m_originalPoints"), list);
  620. }
  621.  
  622. void wxPolygonShape::ReadAttributes(wxExpr *clause)
  623. {
  624.   wxShape::ReadAttributes(clause);
  625.  
  626.   // Read a list of lists
  627.   m_points = new wxList;
  628.   m_originalPoints = new wxList;
  629.  
  630.   wxExpr *points_list = NULL;
  631.   clause->AssignAttributeValue(wxT("points"), &points_list);
  632.  
  633.   // If no points_list, don't crash!! Assume a diamond instead.
  634.   double the_height = 100.0;
  635.   double the_width = 100.0;
  636.   if (!points_list)
  637.   {
  638.     wxRealPoint *point = new wxRealPoint(0.0, (-the_height/2));
  639.     m_points->Append((wxObject*) point);
  640.  
  641.     point = new wxRealPoint((the_width/2), 0.0);
  642.     m_points->Append((wxObject*) point);
  643.  
  644.     point = new wxRealPoint(0.0, (the_height/2));
  645.     m_points->Append((wxObject*) point);
  646.  
  647.     point = new wxRealPoint((-the_width/2), 0.0);
  648.     m_points->Append((wxObject*) point);
  649.  
  650.     point = new wxRealPoint(0.0, (-the_height/2));
  651.     m_points->Append((wxObject*) point);
  652.   }
  653.   else
  654.   {
  655.     wxExpr *node = points_list->value.first;
  656.  
  657.     while (node)
  658.     {
  659.       wxExpr *xexpr = node->value.first;
  660.       long x = xexpr->IntegerValue();
  661.  
  662.       wxExpr *yexpr = xexpr->next;
  663.       long y = yexpr->IntegerValue();
  664.  
  665.       wxRealPoint *point = new wxRealPoint((double)x, (double)y);
  666.       m_points->Append((wxObject*) point);
  667.  
  668.       node = node->next;
  669.     }
  670.   }
  671.  
  672.   points_list = NULL;
  673.   clause->AssignAttributeValue(wxT("m_originalPoints"), &points_list);
  674.  
  675.   // If no points_list, don't crash!! Assume a diamond instead.
  676.   if (!points_list)
  677.   {
  678.     wxRealPoint *point = new wxRealPoint(0.0, (-the_height/2));
  679.     m_originalPoints->Append((wxObject*) point);
  680.  
  681.     point = new wxRealPoint((the_width/2), 0.0);
  682.     m_originalPoints->Append((wxObject*) point);
  683.  
  684.     point = new wxRealPoint(0.0, (the_height/2));
  685.     m_originalPoints->Append((wxObject*) point);
  686.  
  687.     point = new wxRealPoint((-the_width/2), 0.0);
  688.     m_originalPoints->Append((wxObject*) point);
  689.  
  690.     point = new wxRealPoint(0.0, (-the_height/2));
  691.     m_originalPoints->Append((wxObject*) point);
  692.  
  693.     m_originalWidth = the_width;
  694.     m_originalHeight = the_height;
  695.   }
  696.   else
  697.   {
  698.     wxExpr *node = points_list->value.first;
  699.     double min_x = 1000;
  700.     double min_y = 1000;
  701.     double max_x = -1000;
  702.     double max_y = -1000;
  703.     while (node)
  704.     {
  705.       wxExpr *xexpr = node->value.first;
  706.       long x = xexpr->IntegerValue();
  707.  
  708.       wxExpr *yexpr = xexpr->next;
  709.       long y = yexpr->IntegerValue();
  710.  
  711.       wxRealPoint *point = new wxRealPoint((double)x, (double)y);
  712.       m_originalPoints->Append((wxObject*) point);
  713.  
  714.       if (x < min_x)
  715.         min_x = (double)x;
  716.       if (y < min_y)
  717.         min_y = (double)y;
  718.       if (x > max_x)
  719.         max_x = (double)x;
  720.       if (y > max_y)
  721.         max_y = (double)y;
  722.  
  723.       node = node->next;
  724.     }
  725.     m_originalWidth = max_x - min_x;
  726.     m_originalHeight = max_y - min_y;
  727.   }
  728.  
  729.   CalculateBoundingBox();
  730. }
  731. #endif
  732.  
  733. void wxPolygonShape::Copy(wxShape& copy)
  734. {
  735.   wxShape::Copy(copy);
  736.  
  737.   wxASSERT( copy.IsKindOf(CLASSINFO(wxPolygonShape)) );
  738.  
  739.   wxPolygonShape& polyCopy = (wxPolygonShape&) copy;
  740.  
  741.   polyCopy.ClearPoints();
  742.  
  743.   polyCopy.m_points = new wxList;
  744.   polyCopy.m_originalPoints = new wxList;
  745.  
  746.   wxNode *node = m_points->First();
  747.   while (node)
  748.   {
  749.     wxRealPoint *point = (wxRealPoint *)node->Data();
  750.     wxRealPoint *new_point = new wxRealPoint(point->x, point->y);
  751.     polyCopy.m_points->Append((wxObject*) new_point);
  752.     node = node->Next();
  753.   }
  754.   node = m_originalPoints->First();
  755.   while (node)
  756.   {
  757.     wxRealPoint *point = (wxRealPoint *)node->Data();
  758.     wxRealPoint *new_point = new wxRealPoint(point->x, point->y);
  759.     polyCopy.m_originalPoints->Append((wxObject*) new_point);
  760.     node = node->Next();
  761.   }
  762.   polyCopy.m_boundWidth = m_boundWidth;
  763.   polyCopy.m_boundHeight = m_boundHeight;
  764.   polyCopy.m_originalWidth = m_originalWidth;
  765.   polyCopy.m_originalHeight = m_originalHeight;
  766. }
  767.  
  768. int wxPolygonShape::GetNumberOfAttachments() const
  769. {
  770.   int maxN = (m_points ? (m_points->Number() - 1) : 0);
  771.   wxNode *node = m_attachmentPoints.First();
  772.   while (node)
  773.   {
  774.     wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
  775.     if (point->m_id > maxN)
  776.       maxN = point->m_id;
  777.     node = node->Next();
  778.   }
  779.   return maxN+1;;
  780. }
  781.  
  782. bool wxPolygonShape::GetAttachmentPosition(int attachment, double *x, double *y,
  783.                                          int nth, int no_arcs, wxLineShape *line)
  784. {
  785.   if ((m_attachmentMode == ATTACHMENT_MODE_EDGE) && m_points && attachment < m_points->Number())
  786.   {
  787.     wxRealPoint *point = (wxRealPoint *)m_points->Nth(attachment)->Data();
  788.     *x = point->x + m_xpos;
  789.     *y = point->y + m_ypos;
  790.     return TRUE;
  791.   }
  792.   else
  793.   { return wxShape::GetAttachmentPosition(attachment, x, y, nth, no_arcs, line); }
  794. }
  795.  
  796. bool wxPolygonShape::AttachmentIsValid(int attachment)
  797. {
  798.   if (!m_points)
  799.     return FALSE;
  800.  
  801.   if ((attachment >= 0) && (attachment < m_points->Number()))
  802.     return TRUE;
  803.  
  804.   wxNode *node = m_attachmentPoints.First();
  805.   while (node)
  806.   {
  807.     wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
  808.     if (point->m_id == attachment)
  809.       return TRUE;
  810.     node = node->Next();
  811.   }
  812.   return FALSE;
  813. }
  814.  
  815. // Rotate about the given axis by the given amount in radians
  816. void wxPolygonShape::Rotate(double x, double y, double theta)
  817. {
  818.     double actualTheta = theta-m_rotation;
  819.  
  820.     // Rotate attachment points
  821.     double sinTheta = (double)sin(actualTheta);
  822.     double cosTheta = (double)cos(actualTheta);
  823.     wxNode *node = m_attachmentPoints.First();
  824.     while (node)
  825.     {
  826.         wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
  827.         double x1 = point->m_x;
  828.         double y1 = point->m_y;
  829.         point->m_x = x1*cosTheta - y1*sinTheta + x*(1.0 - cosTheta) + y*sinTheta;
  830.         point->m_y = x1*sinTheta + y1*cosTheta + y*(1.0 - cosTheta) + x*sinTheta;
  831.         node = node->Next();
  832.     }
  833.  
  834.     node = m_points->First();
  835.     while (node)
  836.     {
  837.         wxRealPoint *point = (wxRealPoint *)node->Data();
  838.         double x1 = point->x;
  839.         double y1 = point->y;
  840.         point->x = x1*cosTheta - y1*sinTheta + x*(1.0 - cosTheta) + y*sinTheta;
  841.         point->y = x1*sinTheta + y1*cosTheta + y*(1.0 - cosTheta) + x*sinTheta;
  842.         node = node->Next();
  843.     }
  844.     node = m_originalPoints->First();
  845.     while (node)
  846.     {
  847.         wxRealPoint *point = (wxRealPoint *)node->Data();
  848.         double x1 = point->x;
  849.         double y1 = point->y;
  850.         point->x = x1*cosTheta - y1*sinTheta + x*(1.0 - cosTheta) + y*sinTheta;
  851.         point->y = x1*sinTheta + y1*cosTheta + y*(1.0 - cosTheta) + x*sinTheta;
  852.         node = node->Next();
  853.     }
  854.  
  855.     m_rotation = theta;
  856.  
  857.     CalculatePolygonCentre();
  858.     CalculateBoundingBox();
  859.     ResetControlPoints();
  860. }
  861.  
  862. // Rectangle object
  863.  
  864. IMPLEMENT_DYNAMIC_CLASS(wxRectangleShape, wxShape)
  865.  
  866. wxRectangleShape::wxRectangleShape(double w, double h)
  867. {
  868.   m_width = w; m_height = h; m_cornerRadius = 0.0;
  869.   SetDefaultRegionSize();
  870. }
  871.  
  872. void wxRectangleShape::OnDraw(wxDC& dc)
  873. {
  874.     double x1 = (double)(m_xpos - m_width/2.0);
  875.     double y1 = (double)(m_ypos - m_height/2.0);
  876.  
  877.     if (m_shadowMode != SHADOW_NONE)
  878.     {
  879.       if (m_shadowBrush)
  880.         dc.SetBrush(* m_shadowBrush);
  881.       dc.SetPen(* g_oglTransparentPen);
  882.  
  883.       if (m_cornerRadius != 0.0)
  884.         dc.DrawRoundedRectangle(WXROUND(x1 + m_shadowOffsetX), WXROUND(y1 + m_shadowOffsetY),
  885.                                  WXROUND(m_width), WXROUND(m_height), m_cornerRadius);
  886.       else
  887.         dc.DrawRectangle(WXROUND(x1 + m_shadowOffsetX), WXROUND(y1 + m_shadowOffsetY), WXROUND(m_width), WXROUND(m_height));
  888.     }
  889.  
  890.     if (m_pen)
  891.     {
  892.       if (m_pen->GetWidth() == 0)
  893.         dc.SetPen(* g_oglTransparentPen);
  894.       else
  895.         dc.SetPen(* m_pen);
  896.     }
  897.     if (m_brush)
  898.       dc.SetBrush(* m_brush);
  899.  
  900.     if (m_cornerRadius != 0.0)
  901.       dc.DrawRoundedRectangle(WXROUND(x1), WXROUND(y1), WXROUND(m_width), WXROUND(m_height), m_cornerRadius);
  902.     else
  903.       dc.DrawRectangle(WXROUND(x1), WXROUND(y1), WXROUND(m_width), WXROUND(m_height));
  904. }
  905.  
  906. void wxRectangleShape::GetBoundingBoxMin(double *the_width, double *the_height)
  907. {
  908.   *the_width = m_width;
  909.   *the_height = m_height;
  910. }
  911.  
  912. void wxRectangleShape::SetSize(double x, double y, bool recursive)
  913. {
  914.   SetAttachmentSize(x, y);
  915.   m_width = (double)wxMax(x, 1.0);
  916.   m_height = (double)wxMax(y, 1.0);
  917.   SetDefaultRegionSize();
  918. }
  919.  
  920. void wxRectangleShape::SetCornerRadius(double rad)
  921. {
  922.   m_cornerRadius = rad;
  923. }
  924.  
  925. // Assume (x1, y1) is centre of box (most generally, line end at box)
  926. bool wxRectangleShape::GetPerimeterPoint(double x1, double y1,
  927.                                      double x2, double y2,
  928.                                      double *x3, double *y3)
  929. {
  930.   double bound_x, bound_y;
  931.   GetBoundingBoxMax(&bound_x, &bound_y);
  932.   oglFindEndForBox(bound_x, bound_y, m_xpos, m_ypos, x2, y2, x3, y3);
  933.  
  934.   return TRUE;
  935. }
  936.  
  937. #if wxUSE_PROLOGIO
  938. void wxRectangleShape::WriteAttributes(wxExpr *clause)
  939. {
  940.   wxShape::WriteAttributes(clause);
  941.   clause->AddAttributeValue(wxT("x"), m_xpos);
  942.   clause->AddAttributeValue(wxT("y"), m_ypos);
  943.  
  944.   clause->AddAttributeValue(wxT("width"), m_width);
  945.   clause->AddAttributeValue(wxT("height"), m_height);
  946.   if (m_cornerRadius != 0.0)
  947.     clause->AddAttributeValue(wxT("corner"), m_cornerRadius);
  948. }
  949.  
  950. void wxRectangleShape::ReadAttributes(wxExpr *clause)
  951. {
  952.   wxShape::ReadAttributes(clause);
  953.   clause->AssignAttributeValue(wxT("width"), &m_width);
  954.   clause->AssignAttributeValue(wxT("height"), &m_height);
  955.   clause->AssignAttributeValue(wxT("corner"), &m_cornerRadius);
  956.  
  957.   // In case we're reading an old file, set the region's size
  958.   if (m_regions.Number() == 1)
  959.   {
  960.     wxShapeRegion *region = (wxShapeRegion *)m_regions.First()->Data();
  961.     region->SetSize(m_width, m_height);
  962.   }
  963. }
  964. #endif
  965.  
  966. void wxRectangleShape::Copy(wxShape& copy)
  967. {
  968.   wxShape::Copy(copy);
  969.  
  970.   wxASSERT( copy.IsKindOf(CLASSINFO(wxRectangleShape)) );
  971.  
  972.   wxRectangleShape& rectCopy = (wxRectangleShape&) copy;
  973.   rectCopy.m_width = m_width;
  974.   rectCopy.m_height = m_height;
  975.   rectCopy.m_cornerRadius = m_cornerRadius;
  976. }
  977.  
  978. int wxRectangleShape::GetNumberOfAttachments() const
  979. {
  980.   return wxShape::GetNumberOfAttachments();
  981. }
  982.  
  983.  
  984. // There are 4 attachment points on a rectangle - 0 = top, 1 = right, 2 = bottom,
  985. // 3 = left.
  986. bool wxRectangleShape::GetAttachmentPosition(int attachment, double *x, double *y,
  987.                                          int nth, int no_arcs, wxLineShape *line)
  988. {
  989.     return wxShape::GetAttachmentPosition(attachment, x, y, nth, no_arcs, line);
  990. }
  991.  
  992. // Text object (no box)
  993.  
  994. IMPLEMENT_DYNAMIC_CLASS(wxTextShape, wxRectangleShape)
  995.  
  996. wxTextShape::wxTextShape(double width, double height):
  997.   wxRectangleShape(width, height)
  998. {
  999. }
  1000.  
  1001. void wxTextShape::OnDraw(wxDC& dc)
  1002. {
  1003. }
  1004.  
  1005. void wxTextShape::Copy(wxShape& copy)
  1006. {
  1007.   wxRectangleShape::Copy(copy);
  1008. }
  1009.  
  1010. #if wxUSE_PROLOGIO
  1011. void wxTextShape::WriteAttributes(wxExpr *clause)
  1012. {
  1013.   wxRectangleShape::WriteAttributes(clause);
  1014. }
  1015. #endif
  1016.  
  1017. // Ellipse object
  1018.  
  1019. IMPLEMENT_DYNAMIC_CLASS(wxEllipseShape, wxShape)
  1020.  
  1021. wxEllipseShape::wxEllipseShape(double w, double h)
  1022. {
  1023.   m_width = w; m_height = h;
  1024.   SetDefaultRegionSize();
  1025. }
  1026.  
  1027. void wxEllipseShape::GetBoundingBoxMin(double *w, double *h)
  1028. {
  1029.   *w = m_width; *h = m_height;
  1030. }
  1031.  
  1032. bool wxEllipseShape::GetPerimeterPoint(double x1, double y1,
  1033.                                       double x2, double y2,
  1034.                                       double *x3, double *y3)
  1035. {
  1036.   double bound_x, bound_y;
  1037.   GetBoundingBoxMax(&bound_x, &bound_y);
  1038.  
  1039. //  oglFindEndForBox(bound_x, bound_y, m_xpos, m_ypos, x2, y2, x3, y3);
  1040.   oglDrawArcToEllipse(m_xpos, m_ypos, bound_x, bound_y, x2, y2, x1, y1, x3, y3);
  1041.  
  1042.   return TRUE;
  1043. }
  1044.  
  1045. void wxEllipseShape::OnDraw(wxDC& dc)
  1046. {
  1047.     if (m_shadowMode != SHADOW_NONE)
  1048.     {
  1049.       if (m_shadowBrush)
  1050.         dc.SetBrush(* m_shadowBrush);
  1051.       dc.SetPen(* g_oglTransparentPen);
  1052.       dc.DrawEllipse((long) ((m_xpos - GetWidth()/2) + m_shadowOffsetX),
  1053.                       (long) ((m_ypos - GetHeight()/2) + m_shadowOffsetY),
  1054.                       (long) GetWidth(), (long) GetHeight());
  1055.     }
  1056.  
  1057.     if (m_pen)
  1058.     {
  1059.       if (m_pen->GetWidth() == 0)
  1060.         dc.SetPen(* g_oglTransparentPen);
  1061.       else
  1062.         dc.SetPen(* m_pen);
  1063.     }
  1064.     if (m_brush)
  1065.       dc.SetBrush(* m_brush);
  1066.     dc.DrawEllipse((long) (m_xpos - GetWidth()/2), (long) (m_ypos - GetHeight()/2), (long) GetWidth(), (long) GetHeight());
  1067. }
  1068.  
  1069. void wxEllipseShape::SetSize(double x, double y, bool recursive)
  1070. {
  1071.   SetAttachmentSize(x, y);
  1072.   m_width = x;
  1073.   m_height = y;
  1074.   SetDefaultRegionSize();
  1075. }
  1076.  
  1077. #if wxUSE_PROLOGIO
  1078. void wxEllipseShape::WriteAttributes(wxExpr *clause)
  1079. {
  1080.   wxShape::WriteAttributes(clause);
  1081.   clause->AddAttributeValue(wxT("x"), m_xpos);
  1082.   clause->AddAttributeValue(wxT("y"), m_ypos);
  1083.  
  1084.   clause->AddAttributeValue(wxT("width"), m_width);
  1085.   clause->AddAttributeValue(wxT("height"), m_height);
  1086. }
  1087.  
  1088. void wxEllipseShape::ReadAttributes(wxExpr *clause)
  1089. {
  1090.   wxShape::ReadAttributes(clause);
  1091.   clause->AssignAttributeValue(wxT("width"), &m_width);
  1092.   clause->AssignAttributeValue(wxT("height"), &m_height);
  1093.  
  1094.   // In case we're reading an old file, set the region's size
  1095.   if (m_regions.Number() == 1)
  1096.   {
  1097.     wxShapeRegion *region = (wxShapeRegion *)m_regions.First()->Data();
  1098.     region->SetSize(m_width, m_height);
  1099.   }
  1100. }
  1101. #endif
  1102.  
  1103. void wxEllipseShape::Copy(wxShape& copy)
  1104. {
  1105.   wxShape::Copy(copy);
  1106.  
  1107.   wxASSERT( copy.IsKindOf(CLASSINFO(wxEllipseShape)) );
  1108.  
  1109.   wxEllipseShape& ellipseCopy = (wxEllipseShape&) copy;
  1110.  
  1111.   ellipseCopy.m_width = m_width;
  1112.   ellipseCopy.m_height = m_height;
  1113. }
  1114.  
  1115. int wxEllipseShape::GetNumberOfAttachments() const
  1116. {
  1117.   return wxShape::GetNumberOfAttachments();
  1118. }
  1119.  
  1120. // There are 4 attachment points on an ellipse - 0 = top, 1 = right, 2 = bottom,
  1121. // 3 = left.
  1122. bool wxEllipseShape::GetAttachmentPosition(int attachment, double *x, double *y,
  1123.                                          int nth, int no_arcs, wxLineShape *line)
  1124. {
  1125.   if (m_attachmentMode == ATTACHMENT_MODE_BRANCHING)
  1126.     return wxShape::GetAttachmentPosition(attachment, x, y, nth, no_arcs, line);
  1127.  
  1128.   if (m_attachmentMode != ATTACHMENT_MODE_NONE)
  1129.   {
  1130.     double top = (double)(m_ypos + m_height/2.0);
  1131.     double bottom = (double)(m_ypos - m_height/2.0);
  1132.     double left = (double)(m_xpos - m_width/2.0);
  1133.     double right = (double)(m_xpos + m_width/2.0);
  1134.  
  1135.     int physicalAttachment = LogicalToPhysicalAttachment(attachment);
  1136.  
  1137.     switch (physicalAttachment)
  1138.     {
  1139.       case 0:
  1140.       {
  1141.         if (m_spaceAttachments)
  1142.           *x = left + (nth + 1)*m_width/(no_arcs + 1);
  1143.         else *x = m_xpos;
  1144.         *y = top;
  1145.         // We now have the point on the bounding box: but get the point on the ellipse
  1146.         // by imagining a vertical line from (*x, m_ypos - m_height- 500) to (*x, m_ypos) intersecting
  1147.         // the ellipse.
  1148.         oglDrawArcToEllipse(m_xpos, m_ypos, m_width, m_height, *x, (double)(m_ypos-m_height-500), *x, m_ypos, x, y);
  1149.         break;
  1150.       }
  1151.       case 1:
  1152.       {
  1153.         *x = right;
  1154.         if (m_spaceAttachments)
  1155.           *y = bottom + (nth + 1)*m_height/(no_arcs + 1);
  1156.         else *y = m_ypos;
  1157.         oglDrawArcToEllipse(m_xpos, m_ypos, m_width, m_height, (double)(m_xpos+m_width+500), *y, m_xpos, *y, x, y);
  1158.         break;
  1159.       }
  1160.       case 2:
  1161.       {
  1162.         if (m_spaceAttachments)
  1163.           *x = left + (nth + 1)*m_width/(no_arcs + 1);
  1164.         else *x = m_xpos;
  1165.         *y = bottom;
  1166.         oglDrawArcToEllipse(m_xpos, m_ypos, m_width, m_height, *x, (double)(m_ypos+m_height+500), *x, m_ypos, x, y);
  1167.         break;
  1168.       }
  1169.       case 3:
  1170.       {
  1171.         *x = left;
  1172.         if (m_spaceAttachments)
  1173.           *y = bottom + (nth + 1)*m_height/(no_arcs + 1);
  1174.         else *y = m_ypos;
  1175.         oglDrawArcToEllipse(m_xpos, m_ypos, m_width, m_height, (double)(m_xpos-m_width-500), *y, m_xpos, *y, x, y);
  1176.         break;
  1177.       }
  1178.       default:
  1179.       {
  1180.         return wxShape::GetAttachmentPosition(attachment, x, y, nth, no_arcs, line);
  1181.         break;
  1182.       }
  1183.     }
  1184.     return TRUE;
  1185.   }
  1186.   else
  1187.   { *x = m_xpos; *y = m_ypos; return TRUE; }
  1188. }
  1189.  
  1190.  
  1191. // Circle object
  1192. IMPLEMENT_DYNAMIC_CLASS(wxCircleShape, wxEllipseShape)
  1193.  
  1194. wxCircleShape::wxCircleShape(double diameter):wxEllipseShape(diameter, diameter)
  1195. {
  1196.     SetMaintainAspectRatio(TRUE);
  1197. }
  1198.  
  1199. void wxCircleShape::Copy(wxShape& copy)
  1200. {
  1201.   wxEllipseShape::Copy(copy);
  1202. }
  1203.  
  1204. bool wxCircleShape::GetPerimeterPoint(double x1, double y1,
  1205.                                       double x2, double y2,
  1206.                                       double *x3, double *y3)
  1207. {
  1208.   oglFindEndForCircle(m_width/2,
  1209.                       m_xpos, m_ypos,  // Centre of circle
  1210.                       x2, y2,  // Other end of line
  1211.                       x3, y3);
  1212.  
  1213.   return TRUE;
  1214. }
  1215.  
  1216. // Control points
  1217.  
  1218. double wxControlPoint::sm_controlPointDragStartX = 0.0;
  1219. double wxControlPoint::sm_controlPointDragStartY = 0.0;
  1220. double wxControlPoint::sm_controlPointDragStartWidth = 0.0;
  1221. double wxControlPoint::sm_controlPointDragStartHeight = 0.0;
  1222. double wxControlPoint::sm_controlPointDragEndWidth = 0.0;
  1223. double wxControlPoint::sm_controlPointDragEndHeight = 0.0;
  1224. double wxControlPoint::sm_controlPointDragPosX = 0.0;
  1225. double wxControlPoint::sm_controlPointDragPosY = 0.0;
  1226.  
  1227. IMPLEMENT_DYNAMIC_CLASS(wxControlPoint, wxRectangleShape)
  1228.  
  1229. wxControlPoint::wxControlPoint(wxShapeCanvas *theCanvas, wxShape *object, double size, double the_xoffset, double the_yoffset, int the_type):wxRectangleShape(size, size)
  1230. {
  1231.   m_canvas = theCanvas;
  1232.   m_shape = object;
  1233.   m_xoffset = the_xoffset;
  1234.   m_yoffset = the_yoffset;
  1235.   m_type = the_type;
  1236.   SetPen(g_oglBlackForegroundPen);
  1237.   SetBrush(wxBLACK_BRUSH);
  1238.   m_oldCursor = NULL;
  1239.   m_visible = TRUE;
  1240.   m_eraseObject = TRUE;
  1241. }
  1242.  
  1243. wxControlPoint::~wxControlPoint()
  1244. {
  1245. }
  1246.  
  1247. // Don't even attempt to draw any text - waste of time!
  1248. void wxControlPoint::OnDrawContents(wxDC& dc)
  1249. {
  1250. }
  1251.  
  1252. void wxControlPoint::OnDraw(wxDC& dc)
  1253. {
  1254.   m_xpos = m_shape->GetX() + m_xoffset;
  1255.   m_ypos = m_shape->GetY() + m_yoffset;
  1256.   wxRectangleShape::OnDraw(dc);
  1257. }
  1258.  
  1259. void wxControlPoint::OnErase(wxDC& dc)
  1260. {
  1261.   wxRectangleShape::OnErase(dc);
  1262. }
  1263.  
  1264. // Implement resizing of canvas object
  1265. void wxControlPoint::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
  1266. {
  1267.     m_shape->GetEventHandler()->OnSizingDragLeft(this, draw, x, y, keys, attachment);
  1268. }
  1269.  
  1270. void wxControlPoint::OnBeginDragLeft(double x, double y, int keys, int attachment)
  1271. {
  1272.     m_shape->GetEventHandler()->OnSizingBeginDragLeft(this, x, y, keys, attachment);
  1273. }
  1274.  
  1275. void wxControlPoint::OnEndDragLeft(double x, double y, int keys, int attachment)
  1276. {
  1277.     m_shape->GetEventHandler()->OnSizingEndDragLeft(this, x, y, keys, attachment);
  1278. }
  1279.  
  1280. int wxControlPoint::GetNumberOfAttachments() const
  1281. {
  1282.   return 1;
  1283. }
  1284.  
  1285. bool wxControlPoint::GetAttachmentPosition(int attachment, double *x, double *y,
  1286.                                          int nth, int no_arcs, wxLineShape *line)
  1287. {
  1288.   *x = m_xpos; *y = m_ypos;
  1289.   return TRUE;
  1290. }
  1291.  
  1292. // Control points ('handles') redirect control to the actual shape, to make it easier
  1293. // to override sizing behaviour.
  1294. void wxShape::OnSizingDragLeft(wxControlPoint* pt, bool draw, double x, double y, int keys, int attachment)
  1295. {
  1296.   double bound_x;
  1297.   double bound_y;
  1298.   this->GetBoundingBoxMin(&bound_x, &bound_y);
  1299.  
  1300.   wxClientDC dc(GetCanvas());
  1301.   GetCanvas()->PrepareDC(dc);
  1302.  
  1303.   dc.SetLogicalFunction(OGLRBLF);
  1304.  
  1305.   wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
  1306.   dc.SetPen(dottedPen);
  1307.   dc.SetBrush((* wxTRANSPARENT_BRUSH));
  1308.  
  1309.   if (this->GetCentreResize())
  1310.   {
  1311.     // Maintain the same centre point.
  1312.     double new_width = (double)(2.0*fabs(x - this->GetX()));
  1313.     double new_height = (double)(2.0*fabs(y - this->GetY()));
  1314.  
  1315.     // Constrain sizing according to what control point you're dragging
  1316.     if (pt->m_type == CONTROL_POINT_HORIZONTAL)
  1317.     {
  1318.         if (GetMaintainAspectRatio())
  1319.         {
  1320.             new_height = bound_y*(new_width/bound_x);
  1321.         }
  1322.         else
  1323.             new_height = bound_y;
  1324.     }
  1325.     else if (pt->m_type == CONTROL_POINT_VERTICAL)
  1326.     {
  1327.         if (GetMaintainAspectRatio())
  1328.         {
  1329.             new_width = bound_x*(new_height/bound_y);
  1330.         }
  1331.         else
  1332.             new_width = bound_x;
  1333.     }
  1334.     else if (pt->m_type == CONTROL_POINT_DIAGONAL && (keys & KEY_SHIFT))
  1335.       new_height = bound_y*(new_width/bound_x);
  1336.  
  1337.     if (this->GetFixedWidth())
  1338.       new_width = bound_x;
  1339.  
  1340.     if (this->GetFixedHeight())
  1341.       new_height = bound_y;
  1342.  
  1343.     pt->sm_controlPointDragEndWidth = new_width;
  1344.     pt->sm_controlPointDragEndHeight = new_height;
  1345.  
  1346.     this->GetEventHandler()->OnDrawOutline(dc, this->GetX(), this->GetY(),
  1347.                                 new_width, new_height);
  1348.   }
  1349.   else
  1350.   {
  1351.     // Don't maintain the same centre point!
  1352.     double newX1 = wxMin(pt->sm_controlPointDragStartX, x);
  1353.     double newY1 = wxMin(pt->sm_controlPointDragStartY, y);
  1354.     double newX2 = wxMax(pt->sm_controlPointDragStartX, x);
  1355.     double newY2 = wxMax(pt->sm_controlPointDragStartY, y);
  1356.     if (pt->m_type == CONTROL_POINT_HORIZONTAL)
  1357.     {
  1358.       newY1 = pt->sm_controlPointDragStartY;
  1359.       newY2 = newY1 + pt->sm_controlPointDragStartHeight;
  1360.     }
  1361.     else if (pt->m_type == CONTROL_POINT_VERTICAL)
  1362.     {
  1363.       newX1 = pt->sm_controlPointDragStartX;
  1364.       newX2 = newX1 + pt->sm_controlPointDragStartWidth;
  1365.     }
  1366.     else if (pt->m_type == CONTROL_POINT_DIAGONAL && ((keys & KEY_SHIFT) || GetMaintainAspectRatio()))
  1367.     {
  1368.       double newH = (double)((newX2 - newX1)*(pt->sm_controlPointDragStartHeight/pt->sm_controlPointDragStartWidth));
  1369.       if (GetY() > pt->sm_controlPointDragStartY)
  1370.         newY2 = (double)(newY1 + newH);
  1371.       else
  1372.         newY1 = (double)(newY2 - newH);
  1373.     }
  1374.     double newWidth = (double)(newX2 - newX1);
  1375.     double newHeight = (double)(newY2 - newY1);
  1376.  
  1377.     if (pt->m_type == CONTROL_POINT_VERTICAL && GetMaintainAspectRatio())
  1378.     {
  1379.         newWidth = bound_x * (newHeight/bound_y) ;
  1380.     }
  1381.  
  1382.     if (pt->m_type == CONTROL_POINT_HORIZONTAL && GetMaintainAspectRatio())
  1383.     {
  1384.         newHeight = bound_y * (newWidth/bound_x) ;
  1385.     }
  1386.  
  1387.     pt->sm_controlPointDragPosX = (double)(newX1 + (newWidth/2.0));
  1388.     pt->sm_controlPointDragPosY = (double)(newY1 + (newHeight/2.0));
  1389.     if (this->GetFixedWidth())
  1390.       newWidth = bound_x;
  1391.  
  1392.     if (this->GetFixedHeight())
  1393.       newHeight = bound_y;
  1394.  
  1395.     pt->sm_controlPointDragEndWidth = newWidth;
  1396.     pt->sm_controlPointDragEndHeight = newHeight;
  1397.     this->GetEventHandler()->OnDrawOutline(dc, pt->sm_controlPointDragPosX, pt->sm_controlPointDragPosY, newWidth, newHeight);
  1398.   }
  1399. }
  1400.  
  1401. void wxShape::OnSizingBeginDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment)
  1402. {
  1403.   m_canvas->CaptureMouse();
  1404.  
  1405.   wxClientDC dc(GetCanvas());
  1406.   GetCanvas()->PrepareDC(dc);
  1407. /*
  1408.   if (pt->m_eraseObject)
  1409.     this->Erase(dc);
  1410. */
  1411.  
  1412.   dc.SetLogicalFunction(OGLRBLF);
  1413.  
  1414.   double bound_x;
  1415.   double bound_y;
  1416.   this->GetBoundingBoxMin(&bound_x, &bound_y);
  1417.  
  1418.   // Choose the 'opposite corner' of the object as the stationary
  1419.   // point in case this is non-centring resizing.
  1420.   if (pt->GetX() < this->GetX())
  1421.     pt->sm_controlPointDragStartX = (double)(this->GetX() + (bound_x/2.0));
  1422.   else
  1423.     pt->sm_controlPointDragStartX = (double)(this->GetX() - (bound_x/2.0));
  1424.  
  1425.   if (pt->GetY() < this->GetY())
  1426.     pt->sm_controlPointDragStartY = (double)(this->GetY() + (bound_y/2.0));
  1427.   else
  1428.     pt->sm_controlPointDragStartY = (double)(this->GetY() - (bound_y/2.0));
  1429.  
  1430.   if (pt->m_type == CONTROL_POINT_HORIZONTAL)
  1431.     pt->sm_controlPointDragStartY = (double)(this->GetY() - (bound_y/2.0));
  1432.   else if (pt->m_type == CONTROL_POINT_VERTICAL)
  1433.     pt->sm_controlPointDragStartX = (double)(this->GetX() - (bound_x/2.0));
  1434.  
  1435.   // We may require the old width and height.
  1436.   pt->sm_controlPointDragStartWidth = bound_x;
  1437.   pt->sm_controlPointDragStartHeight = bound_y;
  1438.  
  1439.   wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
  1440.   dc.SetPen(dottedPen);
  1441.   dc.SetBrush((* wxTRANSPARENT_BRUSH));
  1442.  
  1443.   if (this->GetCentreResize())
  1444.   {
  1445.     double new_width = (double)(2.0*fabs(x - this->GetX()));
  1446.     double new_height = (double)(2.0*fabs(y - this->GetY()));
  1447.  
  1448.     // Constrain sizing according to what control point you're dragging
  1449.     if (pt->m_type == CONTROL_POINT_HORIZONTAL)
  1450.     {
  1451.         if (GetMaintainAspectRatio())
  1452.         {
  1453.             new_height = bound_y*(new_width/bound_x);
  1454.         }
  1455.         else
  1456.             new_height = bound_y;
  1457.     }
  1458.     else if (pt->m_type == CONTROL_POINT_VERTICAL)
  1459.     {
  1460.         if (GetMaintainAspectRatio())
  1461.         {
  1462.             new_width = bound_x*(new_height/bound_y);
  1463.         }
  1464.         else
  1465.             new_width = bound_x;
  1466.     }
  1467.     else if (pt->m_type == CONTROL_POINT_DIAGONAL && (keys & KEY_SHIFT))
  1468.       new_height = bound_y*(new_width/bound_x);
  1469.  
  1470.     if (this->GetFixedWidth())
  1471.       new_width = bound_x;
  1472.  
  1473.     if (this->GetFixedHeight())
  1474.       new_height = bound_y;
  1475.  
  1476.     pt->sm_controlPointDragEndWidth = new_width;
  1477.     pt->sm_controlPointDragEndHeight = new_height;
  1478.     this->GetEventHandler()->OnDrawOutline(dc, this->GetX(), this->GetY(),
  1479.                                 new_width, new_height);
  1480.   }
  1481.   else
  1482.   {
  1483.     // Don't maintain the same centre point!
  1484.     double newX1 = wxMin(pt->sm_controlPointDragStartX, x);
  1485.     double newY1 = wxMin(pt->sm_controlPointDragStartY, y);
  1486.     double newX2 = wxMax(pt->sm_controlPointDragStartX, x);
  1487.     double newY2 = wxMax(pt->sm_controlPointDragStartY, y);
  1488.     if (pt->m_type == CONTROL_POINT_HORIZONTAL)
  1489.     {
  1490.       newY1 = pt->sm_controlPointDragStartY;
  1491.       newY2 = newY1 + pt->sm_controlPointDragStartHeight;
  1492.     }
  1493.     else if (pt->m_type == CONTROL_POINT_VERTICAL)
  1494.     {
  1495.       newX1 = pt->sm_controlPointDragStartX;
  1496.       newX2 = newX1 + pt->sm_controlPointDragStartWidth;
  1497.     }
  1498.     else if (pt->m_type == CONTROL_POINT_DIAGONAL && ((keys & KEY_SHIFT) || GetMaintainAspectRatio()))
  1499.     {
  1500.       double newH = (double)((newX2 - newX1)*(pt->sm_controlPointDragStartHeight/pt->sm_controlPointDragStartWidth));
  1501.       if (pt->GetY() > pt->sm_controlPointDragStartY)
  1502.         newY2 = (double)(newY1 + newH);
  1503.       else
  1504.         newY1 = (double)(newY2 - newH);
  1505.     }
  1506.     double newWidth = (double)(newX2 - newX1);
  1507.     double newHeight = (double)(newY2 - newY1);
  1508.  
  1509.     if (pt->m_type == CONTROL_POINT_VERTICAL && GetMaintainAspectRatio())
  1510.     {
  1511.         newWidth = bound_x * (newHeight/bound_y) ;
  1512.     }
  1513.  
  1514.     if (pt->m_type == CONTROL_POINT_HORIZONTAL && GetMaintainAspectRatio())
  1515.     {
  1516.         newHeight = bound_y * (newWidth/bound_x) ;
  1517.     }
  1518.  
  1519.     pt->sm_controlPointDragPosX = (double)(newX1 + (newWidth/2.0));
  1520.     pt->sm_controlPointDragPosY = (double)(newY1 + (newHeight/2.0));
  1521.     if (this->GetFixedWidth())
  1522.       newWidth = bound_x;
  1523.  
  1524.     if (this->GetFixedHeight())
  1525.       newHeight = bound_y;
  1526.  
  1527.     pt->sm_controlPointDragEndWidth = newWidth;
  1528.     pt->sm_controlPointDragEndHeight = newHeight;
  1529.     this->GetEventHandler()->OnDrawOutline(dc, pt->sm_controlPointDragPosX, pt->sm_controlPointDragPosY, newWidth, newHeight);
  1530.   }
  1531. }
  1532.  
  1533. void wxShape::OnSizingEndDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment)
  1534. {
  1535.   wxClientDC dc(GetCanvas());
  1536.   GetCanvas()->PrepareDC(dc);
  1537.  
  1538.   m_canvas->ReleaseMouse();
  1539.   dc.SetLogicalFunction(wxCOPY);
  1540.   this->Recompute();
  1541.   this->ResetControlPoints();
  1542.  
  1543.   this->Erase(dc);
  1544. /*
  1545.   if (!pt->m_eraseObject)
  1546.     this->Show(FALSE);
  1547. */
  1548.  
  1549.   this->SetSize(pt->sm_controlPointDragEndWidth, pt->sm_controlPointDragEndHeight);
  1550.  
  1551.   // The next operation could destroy this control point (it does for label objects,
  1552.   // via formatting the text), so save all values we're going to use, or
  1553.   // we'll be accessing garbage.
  1554.   wxShape *theObject = this;
  1555.   wxShapeCanvas *theCanvas = m_canvas;
  1556.   bool eraseIt = pt->m_eraseObject;
  1557.  
  1558.   if (theObject->GetCentreResize())
  1559.     theObject->Move(dc, theObject->GetX(), theObject->GetY());
  1560.   else
  1561.     theObject->Move(dc, pt->sm_controlPointDragPosX, pt->sm_controlPointDragPosY);
  1562.  
  1563. /*
  1564.   if (!eraseIt)
  1565.     theObject->Show(TRUE);
  1566. */
  1567.  
  1568.   // Recursively redraw links if we have a composite.
  1569.   if (theObject->GetChildren().Number() > 0)
  1570.     theObject->DrawLinks(dc, -1, TRUE);
  1571.  
  1572.   double width, height;
  1573.   theObject->GetBoundingBoxMax(&width, &height);
  1574.   theObject->GetEventHandler()->OnEndSize(width, height);
  1575.  
  1576.   if (!theCanvas->GetQuickEditMode() && eraseIt) theCanvas->Redraw(dc);
  1577. }
  1578.  
  1579.  
  1580.  
  1581. // Polygon control points
  1582.  
  1583. IMPLEMENT_DYNAMIC_CLASS(wxPolygonControlPoint, wxControlPoint)
  1584.  
  1585. wxPolygonControlPoint::wxPolygonControlPoint(wxShapeCanvas *theCanvas, wxShape *object, double size,
  1586.   wxRealPoint *vertex, double the_xoffset, double the_yoffset):
  1587.   wxControlPoint(theCanvas, object, size, the_xoffset, the_yoffset, 0)
  1588. {
  1589.   m_polygonVertex = vertex;
  1590.   m_originalDistance = 0.0;
  1591. }
  1592.  
  1593. wxPolygonControlPoint::~wxPolygonControlPoint()
  1594. {
  1595. }
  1596.  
  1597. // Calculate what new size would be, at end of resize
  1598. void wxPolygonControlPoint::CalculateNewSize(double x, double y)
  1599. {
  1600.   double bound_x;
  1601.   double bound_y;
  1602.   GetShape()->GetBoundingBoxMin(&bound_x, &bound_y);
  1603.  
  1604.   double dist = (double)sqrt((x - m_shape->GetX())*(x - m_shape->GetX()) +
  1605.                     (y - m_shape->GetY())*(y - m_shape->GetY()));
  1606.  
  1607.   m_newSize.x = (double)(dist/this->m_originalDistance)*this->m_originalSize.x;
  1608.   m_newSize.y = (double)(dist/this->m_originalDistance)*this->m_originalSize.y;
  1609. }
  1610.  
  1611.  
  1612. // Implement resizing polygon or moving the vertex.
  1613. void wxPolygonControlPoint::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
  1614. {
  1615.     m_shape->GetEventHandler()->OnSizingDragLeft(this, draw, x, y, keys, attachment);
  1616. }
  1617.  
  1618. void wxPolygonControlPoint::OnBeginDragLeft(double x, double y, int keys, int attachment)
  1619. {
  1620.     m_shape->GetEventHandler()->OnSizingBeginDragLeft(this, x, y, keys, attachment);
  1621. }
  1622.  
  1623. void wxPolygonControlPoint::OnEndDragLeft(double x, double y, int keys, int attachment)
  1624. {
  1625.     m_shape->GetEventHandler()->OnSizingEndDragLeft(this, x, y, keys, attachment);
  1626. }
  1627.  
  1628. // Control points ('handles') redirect control to the actual shape, to make it easier
  1629. // to override sizing behaviour.
  1630. void wxPolygonShape::OnSizingDragLeft(wxControlPoint* pt, bool draw, double x, double y, int keys, int attachment)
  1631. {
  1632.   wxPolygonControlPoint* ppt = (wxPolygonControlPoint*) pt;
  1633.  
  1634.   wxClientDC dc(GetCanvas());
  1635.   GetCanvas()->PrepareDC(dc);
  1636.  
  1637.   dc.SetLogicalFunction(OGLRBLF);
  1638.  
  1639.   wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
  1640.   dc.SetPen(dottedPen);
  1641.   dc.SetBrush((* wxTRANSPARENT_BRUSH));
  1642.  
  1643.   if (0) // keys & KEY_CTRL)
  1644.   {
  1645.     // TODO: mend this code. Currently we rely on altering the
  1646.     // actual points, but we should assume we're not, as per
  1647.     // the normal sizing case.
  1648.     m_canvas->Snap(&x, &y);
  1649.  
  1650.     // Move point
  1651.     ppt->m_polygonVertex->x = x - this->GetX();
  1652.     ppt->m_polygonVertex->y = y - this->GetY();
  1653.     ppt->SetX(x);
  1654.     ppt->SetY(y);
  1655.     ((wxPolygonShape *)this)->CalculateBoundingBox();
  1656.     ((wxPolygonShape *)this)->CalculatePolygonCentre();
  1657.   }
  1658.   else
  1659.   {
  1660.     ppt->CalculateNewSize(x, y);
  1661.   }
  1662.  
  1663.   this->GetEventHandler()->OnDrawOutline(dc, this->GetX(), this->GetY(),
  1664.        ppt->GetNewSize().x, ppt->GetNewSize().y);
  1665. }
  1666.  
  1667. void wxPolygonShape::OnSizingBeginDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment)
  1668. {
  1669.   wxPolygonControlPoint* ppt = (wxPolygonControlPoint*) pt;
  1670.  
  1671.   wxClientDC dc(GetCanvas());
  1672.   GetCanvas()->PrepareDC(dc);
  1673.  
  1674.   this->Erase(dc);
  1675.  
  1676.   dc.SetLogicalFunction(OGLRBLF);
  1677.  
  1678.   double bound_x;
  1679.   double bound_y;
  1680.   this->GetBoundingBoxMin(&bound_x, &bound_y);
  1681.  
  1682.   double dist = (double)sqrt((x - this->GetX())*(x - this->GetX()) +
  1683.                     (y - this->GetY())*(y - this->GetY()));
  1684.   ppt->m_originalDistance = dist;
  1685.   ppt->m_originalSize.x = bound_x;
  1686.   ppt->m_originalSize.y = bound_y;
  1687.  
  1688.   if (ppt->m_originalDistance == 0.0) ppt->m_originalDistance = (double) 0.0001;
  1689.  
  1690.   wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
  1691.   dc.SetPen(dottedPen);
  1692.   dc.SetBrush((* wxTRANSPARENT_BRUSH));
  1693.  
  1694.   if (0) // keys & KEY_CTRL)
  1695.   {
  1696.     // TODO: mend this code. Currently we rely on altering the
  1697.     // actual points, but we should assume we're not, as per
  1698.     // the normal sizing case.
  1699.     m_canvas->Snap(&x, &y);
  1700.  
  1701.     // Move point
  1702.     ppt->m_polygonVertex->x = x - this->GetX();
  1703.     ppt->m_polygonVertex->y = y - this->GetY();
  1704.     ppt->SetX(x);
  1705.     ppt->SetY(y);
  1706.     ((wxPolygonShape *)this)->CalculateBoundingBox();
  1707.     ((wxPolygonShape *)this)->CalculatePolygonCentre();
  1708.   }
  1709.   else
  1710.   {
  1711.     ppt->CalculateNewSize(x, y);
  1712.   }
  1713.  
  1714.   this->GetEventHandler()->OnDrawOutline(dc, this->GetX(), this->GetY(),
  1715.        ppt->GetNewSize().x, ppt->GetNewSize().y);
  1716.  
  1717.   m_canvas->CaptureMouse();
  1718. }
  1719.  
  1720. void wxPolygonShape::OnSizingEndDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment)
  1721. {
  1722.   wxPolygonControlPoint* ppt = (wxPolygonControlPoint*) pt;
  1723.  
  1724.   wxClientDC dc(GetCanvas());
  1725.   GetCanvas()->PrepareDC(dc);
  1726.  
  1727.   m_canvas->ReleaseMouse();
  1728.   dc.SetLogicalFunction(wxCOPY);
  1729.  
  1730.   // If we're changing shape, must reset the original points
  1731.   if (keys & KEY_CTRL)
  1732.   {
  1733.     ((wxPolygonShape *)this)->CalculateBoundingBox();
  1734.     ((wxPolygonShape *)this)->UpdateOriginalPoints();
  1735.   }
  1736.   else
  1737.   {
  1738.     SetSize(ppt->GetNewSize().x, ppt->GetNewSize().y);
  1739.   }
  1740.  
  1741.   ((wxPolygonShape *)this)->CalculateBoundingBox();
  1742.   ((wxPolygonShape *)this)->CalculatePolygonCentre();
  1743.  
  1744.   this->Recompute();
  1745.   this->ResetControlPoints();
  1746.   this->Move(dc, this->GetX(), this->GetY());
  1747.   if (!m_canvas->GetQuickEditMode()) m_canvas->Redraw(dc);
  1748. }
  1749.  
  1750. /*
  1751.  * Object region
  1752.  *
  1753.  */
  1754. IMPLEMENT_DYNAMIC_CLASS(wxShapeRegion, wxObject)
  1755.  
  1756. wxShapeRegion::wxShapeRegion()
  1757. {
  1758.   m_regionText = wxEmptyString;
  1759.   m_font = g_oglNormalFont;
  1760.   m_minHeight = 5.0;
  1761.   m_minWidth = 5.0;
  1762.   m_width = 0.0;
  1763.   m_height = 0.0;
  1764.   m_x = 0.0;
  1765.   m_y = 0.0;
  1766.  
  1767.   m_regionProportionX = -1.0;
  1768.   m_regionProportionY = -1.0;
  1769.   m_formatMode = FORMAT_CENTRE_HORIZ | FORMAT_CENTRE_VERT;
  1770.   m_regionName = wxEmptyString;
  1771.   m_textColour = wxT("BLACK");
  1772.   m_penColour = wxT("BLACK");
  1773.   m_penStyle = wxSOLID;
  1774.   m_actualColourObject = NULL;
  1775.   m_actualPenObject = NULL;
  1776. }
  1777.  
  1778. wxShapeRegion::wxShapeRegion(wxShapeRegion& region)
  1779. {
  1780.   m_regionText = region.m_regionText;
  1781.   m_regionName = region.m_regionName;
  1782.   m_textColour = region.m_textColour;
  1783.  
  1784.   m_font = region.m_font;
  1785.   m_minHeight = region.m_minHeight;
  1786.   m_minWidth = region.m_minWidth;
  1787.   m_width = region.m_width;
  1788.   m_height = region.m_height;
  1789.   m_x = region.m_x;
  1790.   m_y = region.m_y;
  1791.  
  1792.   m_regionProportionX = region.m_regionProportionX;
  1793.   m_regionProportionY = region.m_regionProportionY;
  1794.   m_formatMode = region.m_formatMode;
  1795.   m_actualColourObject = NULL;
  1796.   m_actualPenObject = NULL;
  1797.   m_penStyle = region.m_penStyle;
  1798.   m_penColour = region.m_penColour;
  1799.  
  1800.   ClearText();
  1801.   wxNode *node = region.m_formattedText.First();
  1802.   while (node)
  1803.   {
  1804.     wxShapeTextLine *line = (wxShapeTextLine *)node->Data();
  1805.     wxShapeTextLine *new_line =
  1806.       new wxShapeTextLine(line->GetX(), line->GetY(), line->GetText());
  1807.     m_formattedText.Append(new_line);
  1808.     node = node->Next();
  1809.   }
  1810. }
  1811.  
  1812. wxShapeRegion::~wxShapeRegion()
  1813. {
  1814.   ClearText();
  1815. }
  1816.  
  1817. void wxShapeRegion::ClearText()
  1818. {
  1819.   wxNode *node = m_formattedText.First();
  1820.   while (node)
  1821.   {
  1822.     wxShapeTextLine *line = (wxShapeTextLine *)node->Data();
  1823.     wxNode *next = node->Next();
  1824.     delete line;
  1825.     delete node;
  1826.     node = next;
  1827.   }
  1828. }
  1829.  
  1830. void wxShapeRegion::SetFont(wxFont *f)
  1831. {
  1832.   m_font = f;
  1833. }
  1834.  
  1835. void wxShapeRegion::SetMinSize(double w, double h)
  1836. {
  1837.   m_minWidth = w;
  1838.   m_minHeight = h;
  1839. }
  1840.  
  1841. void wxShapeRegion::SetSize(double w, double h)
  1842. {
  1843.   m_width = w;
  1844.   m_height = h;
  1845. }
  1846.  
  1847. void wxShapeRegion::SetPosition(double xp, double yp)
  1848. {
  1849.   m_x = xp;
  1850.   m_y = yp;
  1851. }
  1852.  
  1853. void wxShapeRegion::SetProportions(double xp, double yp)
  1854. {
  1855.   m_regionProportionX = xp;
  1856.   m_regionProportionY = yp;
  1857. }
  1858.  
  1859. void wxShapeRegion::SetFormatMode(int mode)
  1860. {
  1861.   m_formatMode = mode;
  1862. }
  1863.  
  1864. void wxShapeRegion::SetColour(const wxString& col)
  1865. {
  1866.   m_textColour = col;
  1867.   m_actualColourObject = NULL;
  1868. }
  1869.  
  1870. wxColour *wxShapeRegion::GetActualColourObject()
  1871. {
  1872.   if (!m_actualColourObject)
  1873.     m_actualColourObject = wxTheColourDatabase->FindColour(GetColour());
  1874.   if (!m_actualColourObject)
  1875.     m_actualColourObject = wxBLACK;
  1876.   return m_actualColourObject;
  1877. }
  1878.  
  1879. void wxShapeRegion::SetPenColour(const wxString& col)
  1880. {
  1881.   m_penColour = col;
  1882.   m_actualPenObject = NULL;
  1883. }
  1884.  
  1885. // Returns NULL if the pen is invisible
  1886. // (different to pen being transparent; indicates that
  1887. // region boundary should not be drawn.)
  1888. wxPen *wxShapeRegion::GetActualPen()
  1889. {
  1890.   if (m_actualPenObject)
  1891.     return m_actualPenObject;
  1892.  
  1893.   if (!m_penColour) return NULL;
  1894.   if (m_penColour == wxT("Invisible"))
  1895.     return NULL;
  1896.   m_actualPenObject = wxThePenList->FindOrCreatePen(m_penColour, 1, m_penStyle);
  1897.   return m_actualPenObject;
  1898. }
  1899.  
  1900.  
  1901.