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