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 / divided.cpp < prev    next >
C/C++ Source or Header  |  2002-12-18  |  20KB  |  721 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        divided.cpp
  3. // Purpose:     wxDividedShape class
  4. // Author:      Julian Smart
  5. // Modified by:
  6. // Created:     12/07/98
  7. // RCS-ID:      $Id: divided.cpp,v 1.3.2.2 2002/12/18 06:13:00 RD Exp $
  8. // Copyright:   (c) Julian Smart
  9. // Licence:       wxWindows licence
  10. /////////////////////////////////////////////////////////////////////////////
  11.  
  12. #ifdef __GNUG__
  13. #pragma implementation "divided.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. #include <wx/ogl/basic.h>
  30. #include <wx/ogl/basicp.h>
  31. #include <wx/ogl/canvas.h>
  32. #include <wx/ogl/divided.h>
  33. #include <wx/ogl/lines.h>
  34. #include <wx/ogl/misc.h>
  35.  
  36. class wxDividedShapeControlPoint: public wxControlPoint
  37. {
  38.  DECLARE_DYNAMIC_CLASS(wxDividedShapeControlPoint)
  39.  private:
  40.   int regionId;
  41.  public:
  42.   wxDividedShapeControlPoint() { regionId = 0; }
  43.   wxDividedShapeControlPoint(wxShapeCanvas *the_canvas, wxShape *object, int region,
  44.                             double size, double the_xoffset, double the_yoffset, int the_type);
  45.   ~wxDividedShapeControlPoint();
  46.  
  47.   void OnDragLeft(bool draw, double x, double y, int keys=0, int attachment = 0);
  48.   void OnBeginDragLeft(double x, double y, int keys=0, int attachment = 0);
  49.   void OnEndDragLeft(double x, double y, int keys=0, int attachment = 0);
  50. };
  51.  
  52. IMPLEMENT_DYNAMIC_CLASS(wxDividedShapeControlPoint, wxControlPoint)
  53.  
  54. /*
  55.  * Divided object
  56.  *
  57.  */
  58.  
  59. IMPLEMENT_DYNAMIC_CLASS(wxDividedShape, wxRectangleShape)
  60.  
  61. wxDividedShape::wxDividedShape(double w, double h): wxRectangleShape(w, h)
  62. {
  63.   ClearRegions();
  64. }
  65.  
  66. wxDividedShape::~wxDividedShape()
  67. {
  68. }
  69.  
  70. void wxDividedShape::OnDraw(wxDC& dc)
  71. {
  72.   wxRectangleShape::OnDraw(dc);
  73. }
  74.  
  75. void wxDividedShape::OnDrawContents(wxDC& dc)
  76. {
  77.   double defaultProportion = (double)(GetRegions().Number() > 0 ? (1.0/((double)(GetRegions().Number()))) : 0.0);
  78.   double currentY = (double)(m_ypos - (m_height / 2.0));
  79.   double maxY = (double)(m_ypos + (m_height / 2.0));
  80.  
  81.   double leftX = (double)(m_xpos - (m_width / 2.0));
  82.   double rightX = (double)(m_xpos + (m_width / 2.0));
  83.  
  84.   if (m_pen) dc.SetPen(* m_pen);
  85.  
  86.   if (m_textColour) dc.SetTextForeground(* m_textColour);
  87.  
  88. #ifdef __WXMSW__
  89.   // For efficiency, don't do this under X - doesn't make
  90.   // any visible difference for our purposes.
  91.   if (m_brush)
  92.     dc.SetTextBackground(m_brush->GetColour());
  93. #endif
  94. /*
  95.   if (!formatted)
  96.   {
  97.     FormatRegionText();
  98.     formatted = TRUE;
  99.   }
  100. */
  101.   if (GetDisableLabel()) return;
  102.  
  103.   double xMargin = 2;
  104.   double yMargin = 2;
  105.   dc.SetBackgroundMode(wxTRANSPARENT);
  106.  
  107.   wxNode *node = GetRegions().First();
  108.   while (node)
  109.   {
  110.     wxShapeRegion *region = (wxShapeRegion *)node->Data();
  111.     dc.SetFont(* region->GetFont());
  112.     dc.SetTextForeground(* region->GetActualColourObject());
  113.  
  114.     double proportion =
  115.       region->m_regionProportionY < 0.0 ? defaultProportion : region->m_regionProportionY;
  116.  
  117.     double y = currentY + m_height*proportion;
  118.     double actualY = maxY < y ? maxY : y;
  119.  
  120.     double centreX = m_xpos;
  121.     double centreY = (double)(currentY + (actualY - currentY)/2.0);
  122.  
  123.     oglDrawFormattedText(dc, ®ion->m_formattedText,
  124.              (double)(centreX), (double)(centreY), (double)(m_width-2*xMargin), (double)(actualY - currentY - 2*yMargin),
  125.              region->m_formatMode);
  126.     if ((y <= maxY) && (node->Next()))
  127.     {
  128.       wxPen *regionPen = region->GetActualPen();
  129.       if (regionPen)
  130.       {
  131.         dc.SetPen(* regionPen);
  132.         dc.DrawLine(WXROUND(leftX), WXROUND(y), WXROUND(rightX), WXROUND(y));
  133.       }
  134.     }
  135.  
  136.     currentY = actualY;
  137.  
  138.     node = node->Next();
  139.   }
  140. }
  141.  
  142. void wxDividedShape::SetSize(double w, double h, bool recursive)
  143. {
  144.   SetAttachmentSize(w, h);
  145.   m_width = w;
  146.   m_height = h;
  147.   SetRegionSizes();
  148. }
  149.  
  150. void wxDividedShape::SetRegionSizes()
  151. {
  152.   if (GetRegions().Number() == 0)
  153.     return;
  154.  
  155.   double defaultProportion = (double)(GetRegions().Number() > 0 ? (1.0/((double)(GetRegions().Number()))) : 0.0);
  156.   double currentY = (double)(m_ypos - (m_height / 2.0));
  157.   double maxY = (double)(m_ypos + (m_height / 2.0));
  158.  
  159. //  double leftX = (double)(m_xpos - (m_width / 2.0));
  160. //  double rightX = (double)(m_xpos + (m_width / 2.0));
  161.  
  162.   wxNode *node = GetRegions().First();
  163.   while (node)
  164.   {
  165.     wxShapeRegion *region = (wxShapeRegion *)node->Data();
  166.     double proportion =
  167.       region->m_regionProportionY <= 0.0 ? defaultProportion : region->m_regionProportionY;
  168.  
  169.     double sizeY = (double)proportion*m_height;
  170.     double y = currentY + sizeY;
  171.     double actualY = maxY < y ? maxY : y;
  172.  
  173.     double centreY = (double)(currentY + (actualY - currentY)/2.0);
  174.  
  175.     region->SetSize(m_width, sizeY);
  176.     region->SetPosition(0.0, (double)(centreY - m_ypos));
  177.     currentY = actualY;
  178.     node = node->Next();
  179.   }
  180. }
  181.  
  182. // Attachment points correspond to regions in the divided box
  183. bool wxDividedShape::GetAttachmentPosition(int attachment, double *x, double *y, int nth, int no_arcs,
  184.   wxLineShape *line)
  185. {
  186.   int totalNumberAttachments = (GetRegions().Number() * 2) + 2;
  187.   if ((GetAttachmentMode() == ATTACHMENT_MODE_NONE) || (attachment >= totalNumberAttachments))
  188.   {
  189.     return wxShape::GetAttachmentPosition(attachment, x, y, nth, no_arcs);
  190.   }
  191.  
  192.   int n = GetRegions().Number();
  193.   bool isEnd = (line && line->IsEnd(this));
  194.  
  195.   double left = (double)(m_xpos - m_width/2.0);
  196.   double right = (double)(m_xpos + m_width/2.0);
  197.   double top = (double)(m_ypos - m_height/2.0);
  198.   double bottom = (double)(m_ypos + m_height/2.0);
  199.  
  200.   // Zero is top, n+1 is bottom.
  201.   if (attachment == 0)
  202.   {
  203.     *y = top;
  204.     if (m_spaceAttachments)
  205.     {
  206.       if (line && (line->GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE))
  207.       {
  208.         // Align line according to the next handle along
  209.         wxRealPoint *point = line->GetNextControlPoint(this);
  210.         if (point->x < left)
  211.           *x = left;
  212.         else if (point->x > right)
  213.           *x = right;
  214.         else
  215.           *x = point->x;
  216.       }
  217.       else
  218.         *x = left + (nth + 1)*m_width/(no_arcs + 1);
  219.     }
  220.     else
  221.       *x = m_xpos;
  222.   }
  223.   else if (attachment == (n+1))
  224.   {
  225.     *y = bottom;
  226.     if (m_spaceAttachments)
  227.     {
  228.       if (line && (line->GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE))
  229.       {
  230.         // Align line according to the next handle along
  231.         wxRealPoint *point = line->GetNextControlPoint(this);
  232.         if (point->x < left)
  233.           *x = left;
  234.         else if (point->x > right)
  235.           *x = right;
  236.         else
  237.           *x = point->x;
  238.       }
  239.       else
  240.         *x = left + (nth + 1)*m_width/(no_arcs + 1);
  241.     }
  242.     else
  243.       *x = m_xpos;
  244.   }
  245.   // Left or right.
  246.   else
  247.   {
  248.     int i = 0;
  249.     bool isLeft = FALSE;
  250.     if (attachment < (n+1))
  251.     {
  252.       i = attachment-1;
  253.       isLeft = FALSE;
  254.     }
  255.     else
  256.     {
  257.       i = (totalNumberAttachments - attachment - 1);
  258.       isLeft = TRUE;
  259.     }
  260.     wxNode *node = GetRegions().Nth(i);
  261.     if (node)
  262.     {
  263.       wxShapeRegion *region = (wxShapeRegion *)node->Data();
  264.  
  265.       if (isLeft)
  266.         *x = left;
  267.       else
  268.         *x = right;
  269.  
  270.       // Calculate top and bottom of region
  271.       top = (double)((m_ypos + region->m_y) - (region->m_height/2.0));
  272.       bottom = (double)((m_ypos + region->m_y) + (region->m_height/2.0));
  273.  
  274.       // Assuming we can trust the absolute size and
  275.       // position of these regions...
  276.       if (m_spaceAttachments)
  277.       {
  278.         if (line && (line->GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE))
  279.         {
  280.           // Align line according to the next handle along
  281.           wxRealPoint *point = line->GetNextControlPoint(this);
  282.           if (point->y < bottom)
  283.             *y = bottom;
  284.           else if (point->y > top)
  285.             *y = top;
  286.           else
  287.             *y = point->y;
  288.         }
  289.         else
  290. //          *y = (double)(((m_ypos + region->m_y) - (region->m_height/2.0)) + (nth + 1)*region->m_height/(no_arcs+1));
  291.           *y = (double)(top + (nth + 1)*region->m_height/(no_arcs+1));
  292.       }
  293.       else
  294.         *y = (double)(m_ypos + region->m_y);
  295.     }
  296.     else
  297.     {
  298.       *x = m_xpos;
  299.       *y = m_ypos;
  300.       return FALSE;
  301.     }
  302.   }
  303.   return TRUE;
  304. }
  305.  
  306. int wxDividedShape::GetNumberOfAttachments() const
  307. {
  308.   // There are two attachments for each region (left and right),
  309.   // plus one on the top and one on the bottom.
  310.   int n = (GetRegions().Number() * 2) + 2;
  311.  
  312.   int maxN = n - 1;
  313.   wxNode *node = m_attachmentPoints.First();
  314.   while (node)
  315.   {
  316.     wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
  317.     if (point->m_id > maxN)
  318.       maxN = point->m_id;
  319.     node = node->Next();
  320.   }
  321.   return maxN + 1;
  322. }
  323.  
  324. bool wxDividedShape::AttachmentIsValid(int attachment)
  325. {
  326.   int totalNumberAttachments = (GetRegions().Number() * 2) + 2;
  327.   if (attachment >= totalNumberAttachments)
  328.   {
  329.     return wxShape::AttachmentIsValid(attachment);
  330.   }
  331.   else if (attachment >= 0)
  332.     return TRUE;
  333.   else
  334.     return FALSE;
  335. }
  336.  
  337. void wxDividedShape::Copy(wxShape& copy)
  338. {
  339.   wxRectangleShape::Copy(copy);
  340. }
  341.  
  342. // Region operations
  343.  
  344. void wxDividedShape::MakeControlPoints()
  345. {
  346.   wxRectangleShape::MakeControlPoints();
  347.  
  348.   MakeMandatoryControlPoints();
  349. }
  350.  
  351. void wxDividedShape::MakeMandatoryControlPoints()
  352. {
  353.   double currentY = (double)(GetY() - (m_height / 2.0));
  354.   double maxY = (double)(GetY() + (m_height / 2.0));
  355.  
  356.   wxNode *node = GetRegions().First();
  357.   int i = 0;
  358.   while (node)
  359.   {
  360.     wxShapeRegion *region = (wxShapeRegion *)node->Data();
  361.  
  362.     double proportion = region->m_regionProportionY;
  363.  
  364.     double y = currentY + m_height*proportion;
  365.     double actualY = (double)(maxY < y ? maxY : y);
  366.  
  367.     if (node->Next())
  368.     {
  369.       wxDividedShapeControlPoint *controlPoint =
  370.         new wxDividedShapeControlPoint(m_canvas, this, i, CONTROL_POINT_SIZE, 0.0, (double)(actualY - GetY()), 0);
  371.       m_canvas->AddShape(controlPoint);
  372.       m_controlPoints.Append(controlPoint);
  373.     }
  374.     currentY = actualY;
  375.     i ++;
  376.     node = node->Next();
  377.   }
  378. }
  379.  
  380. void wxDividedShape::ResetControlPoints()
  381. {
  382.   // May only have the region handles, (n - 1) of them.
  383.   if (m_controlPoints.Number() > (GetRegions().Number() - 1))
  384.     wxRectangleShape::ResetControlPoints();
  385.  
  386.   ResetMandatoryControlPoints();
  387. }
  388.  
  389. void wxDividedShape::ResetMandatoryControlPoints()
  390. {
  391.   double currentY = (double)(GetY() - (m_height / 2.0));
  392.   double maxY = (double)(GetY() + (m_height / 2.0));
  393.  
  394.   wxNode *node = m_controlPoints.First();
  395.   int i = 0;
  396.   while (node)
  397.   {
  398.     wxControlPoint *controlPoint = (wxControlPoint *)node->Data();
  399.     if (controlPoint->IsKindOf(CLASSINFO(wxDividedShapeControlPoint)))
  400.     {
  401.       wxNode *node1 = GetRegions().Nth(i);
  402.       wxShapeRegion *region = (wxShapeRegion *)node1->Data();
  403.  
  404.       double proportion = region->m_regionProportionY;
  405.  
  406.       double y = currentY + m_height*proportion;
  407.       double actualY = (double)(maxY < y ? maxY : y);
  408.  
  409.       controlPoint->m_xoffset = 0.0;
  410.       controlPoint->m_yoffset = (double)(actualY - GetY());
  411.       currentY = actualY;
  412.       i ++;
  413.     }
  414.     node = node->Next();
  415.   }
  416. }
  417.  
  418. #if wxUSE_PROLOGIO
  419. void wxDividedShape::WriteAttributes(wxExpr *clause)
  420. {
  421.   wxRectangleShape::WriteAttributes(clause);
  422. }
  423.  
  424. void wxDividedShape::ReadAttributes(wxExpr *clause)
  425. {
  426.   wxRectangleShape::ReadAttributes(clause);
  427. }
  428. #endif
  429.  
  430. /*
  431.  * Edit the division colour/style
  432.  *
  433.  */
  434.  
  435. void wxDividedShape::EditRegions()
  436. {
  437.   wxMessageBox(wxT("EditRegions() is unimplemented."), wxT("OGL"), wxOK);
  438.  
  439.   // TODO
  440. #if 0
  441.   if (GetRegions().Number() < 2)
  442.     return;
  443.  
  444.   wxBeginBusyCursor();
  445.  
  446.   GraphicsForm *form = new GraphicsForm("Divided nodes");
  447.   // Need an array to store all the style strings,
  448.   // since they need to be converted to integers
  449.   char **styleStrings = new char *[GetRegions().Number()];
  450.   for (int j = 0; j < GetRegions().Number(); j++)
  451.     styleStrings[j] = NULL;
  452.  
  453.   int i = 0;
  454.   wxNode *node = GetRegions().First();
  455.   while (node && node->Next())
  456.   {
  457.     wxShapeRegion *region = (wxShapeRegion *)node->Data();
  458.     char buf[50];
  459.     sprintf(buf, "Region %d", (i+1));
  460.     form->Add(wxMakeFormMessage(buf));
  461.     form->Add(wxMakeFormNewLine());
  462.  
  463.     form->Add(wxMakeFormString("Colour", ®ion->penColour, wxFORM_CHOICE,
  464.               new wxList(wxMakeConstraintStrings(
  465.     "Invisible"        ,
  466.     "BLACK"            ,
  467.     "BLUE"             ,
  468.     "BROWN"            ,
  469.     "CORAL"            ,
  470.     "CYAN"             ,
  471.     "DARK GREY"        ,
  472.     "DARK GREEN"       ,
  473.     "DIM GREY"         ,
  474.     "GREY"             ,
  475.     "GREEN"            ,
  476.     "LIGHT BLUE"       ,
  477.     "LIGHT GREY"       ,
  478.     "MAGENTA"          ,
  479.     "MAROON"           ,
  480.     "NAVY"             ,
  481.     "ORANGE"           ,
  482.     "PURPLE"           ,
  483.     "RED"              ,
  484.     "TURQUOISE"        ,
  485.     "VIOLET"           ,
  486.     "WHITE"            ,
  487.     "YELLOW"           ,
  488.     NULL),
  489.     NULL), NULL, wxVERTICAL, 150));
  490.  
  491.     char *styleString = NULL;
  492.     switch (region->penStyle)
  493.     {
  494.       case wxSHORT_DASH:
  495.         styleString = "Short Dash";
  496.         break;
  497.       case wxLONG_DASH:
  498.         styleString = "Long Dash";
  499.         break;
  500.       case wxDOT:
  501.         styleString = "Dot";
  502.         break;
  503.       case wxDOT_DASH:
  504.         styleString = "Dot Dash";
  505.         break;
  506.       case wxSOLID:
  507.       default:
  508.         styleString = "Solid";
  509.         break;
  510.     }
  511.     styleStrings[i] = copystring(styleString);
  512.     form->Add(wxMakeFormString("Style", &(styleStrings[i]), wxFORM_CHOICE,
  513.               new wxList(wxMakeConstraintStrings(
  514.     "Solid"            ,
  515.     "Short Dash"       ,
  516.     "Long Dash"        ,
  517.     "Dot"              ,
  518.     "Dot Dash"         ,
  519.     NULL),
  520.     NULL), NULL, wxVERTICAL, 100));
  521.     node = node->Next();
  522.     i ++;
  523.     if (node && node->Next())
  524.       form->Add(wxMakeFormNewLine());
  525.   }
  526.   wxDialogBox *dialog = new wxDialogBox(m_canvas->GetParent(), "Divided object properties", 10, 10, 500, 500);
  527.   if (GraphicsLabelFont)
  528.     dialog->SetLabelFont(GraphicsLabelFont);
  529.   if (GraphicsButtonFont)
  530.     dialog->SetButtonFont(GraphicsButtonFont);
  531.   form->AssociatePanel(dialog);
  532.   form->dialog = dialog;
  533.  
  534.   dialog->Fit();
  535.   dialog->Centre(wxBOTH);
  536.  
  537.   wxEndBusyCursor();
  538.  
  539.   dialog->Show(TRUE);
  540.  
  541.   node = GetRegions().First();
  542.   i = 0;
  543.   while (node)
  544.   {
  545.     wxShapeRegion *region = (wxShapeRegion *)node->Data();
  546.  
  547.     if (styleStrings[i])
  548.     {
  549.       if (strcmp(styleStrings[i], "Solid") == 0)
  550.         region->penStyle = wxSOLID;
  551.       else if (strcmp(styleStrings[i], "Dot") == 0)
  552.         region->penStyle = wxDOT;
  553.       else if (strcmp(styleStrings[i], "Short Dash") == 0)
  554.         region->penStyle = wxSHORT_DASH;
  555.       else if (strcmp(styleStrings[i], "Long Dash") == 0)
  556.         region->penStyle = wxLONG_DASH;
  557.       else if (strcmp(styleStrings[i], "Dot Dash") == 0)
  558.         region->penStyle = wxDOT_DASH;
  559.       delete[] styleStrings[i];
  560.     }
  561.     region->m_actualPenObject = NULL;
  562.     node = node->Next();
  563.     i ++;
  564.   }
  565.   delete[] styleStrings;
  566.   Draw(dc);
  567. #endif
  568. }
  569.  
  570. void wxDividedShape::OnRightClick(double x, double y, int keys, int attachment)
  571. {
  572.   if (keys & KEY_CTRL)
  573.   {
  574.     EditRegions();
  575.   }
  576.   else
  577.   {
  578.     wxRectangleShape::OnRightClick(x, y, keys, attachment);
  579.   }
  580. }
  581.  
  582. wxDividedShapeControlPoint::wxDividedShapeControlPoint(wxShapeCanvas *the_canvas, wxShape *object,
  583.   int region, double size, double the_m_xoffset, double the_m_yoffset, int the_type):
  584.     wxControlPoint(the_canvas, object, size, the_m_xoffset, the_m_yoffset, the_type)
  585. {
  586.   regionId = region;
  587. }
  588.  
  589. wxDividedShapeControlPoint::~wxDividedShapeControlPoint()
  590. {
  591. }
  592.  
  593. // Implement resizing of divided object division
  594. void wxDividedShapeControlPoint::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
  595. {
  596.     wxClientDC dc(GetCanvas());
  597.     GetCanvas()->PrepareDC(dc);
  598.  
  599.     dc.SetLogicalFunction(OGLRBLF);
  600.     wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
  601.     dc.SetPen(dottedPen);
  602.     dc.SetBrush((* wxTRANSPARENT_BRUSH));
  603.  
  604.     wxDividedShape *dividedObject = (wxDividedShape *)m_shape;
  605.     double x1 = (double)(dividedObject->GetX() - (dividedObject->GetWidth()/2.0));
  606.     double y1 = y;
  607.     double x2 = (double)(dividedObject->GetX() + (dividedObject->GetWidth()/2.0));
  608.     double y2 = y;
  609.     dc.DrawLine(WXROUND(x1), WXROUND(y1), WXROUND(x2), WXROUND(y2));
  610. }
  611.  
  612. void wxDividedShapeControlPoint::OnBeginDragLeft(double x, double y, int keys, int attachment)
  613. {
  614.     wxClientDC dc(GetCanvas());
  615.     GetCanvas()->PrepareDC(dc);
  616.  
  617.     wxDividedShape *dividedObject = (wxDividedShape *)m_shape;
  618.     dc.SetLogicalFunction(OGLRBLF);
  619.     wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
  620.     dc.SetPen(dottedPen);
  621.     dc.SetBrush((* wxTRANSPARENT_BRUSH));
  622.  
  623.     double x1 = (double)(dividedObject->GetX() - (dividedObject->GetWidth()/2.0));
  624.     double y1 = y;
  625.     double x2 = (double)(dividedObject->GetX() + (dividedObject->GetWidth()/2.0));
  626.     double y2 = y;
  627.     dc.DrawLine(WXROUND(x1), WXROUND(y1), WXROUND(x2), WXROUND(y2));
  628.     m_canvas->CaptureMouse();
  629. }
  630.  
  631. void wxDividedShapeControlPoint::OnEndDragLeft(double x, double y, int keys, int attachment)
  632. {
  633.     wxClientDC dc(GetCanvas());
  634.     GetCanvas()->PrepareDC(dc);
  635.  
  636.     wxDividedShape *dividedObject = (wxDividedShape *)m_shape;
  637.     wxNode *node = dividedObject->GetRegions().Nth(regionId);
  638.     if (!node)
  639.     return;
  640.  
  641.     wxShapeRegion *thisRegion = (wxShapeRegion *)node->Data();
  642.     wxShapeRegion *nextRegion = NULL; // Region below this one
  643.  
  644.     dc.SetLogicalFunction(wxCOPY);
  645.  
  646.     m_canvas->ReleaseMouse();
  647.  
  648.     // Find the old top and bottom of this region,
  649.     // and calculate the new proportion for this region
  650.     // if legal.
  651.  
  652.     double currentY = (double)(dividedObject->GetY() - (dividedObject->GetHeight() / 2.0));
  653.     double maxY = (double)(dividedObject->GetY() + (dividedObject->GetHeight() / 2.0));
  654.  
  655.     // Save values
  656.     double thisRegionTop = 0.0;
  657.     double thisRegionBottom = 0.0;
  658.     double nextRegionBottom = 0.0;
  659.  
  660.     node = dividedObject->GetRegions().First();
  661.     while (node)
  662.     {
  663.       wxShapeRegion *region = (wxShapeRegion *)node->Data();
  664.  
  665.       double proportion = region->m_regionProportionY;
  666.       double yy = currentY + (dividedObject->GetHeight()*proportion);
  667.       double actualY = (double)(maxY < yy ? maxY : yy);
  668.  
  669.       if (region == thisRegion)
  670.       {
  671.         thisRegionTop = currentY;
  672.         thisRegionBottom = actualY;
  673.         if (node->Next())
  674.           nextRegion = (wxShapeRegion *)node->Next()->Data();
  675.       }
  676.       if (region == nextRegion)
  677.       {
  678.         nextRegionBottom = actualY;
  679.       }
  680.  
  681.       currentY = actualY;
  682.       node = node->Next();
  683.     }
  684.     if (!nextRegion)
  685.       return;
  686.  
  687.     // Check that we haven't gone above this region or below
  688.     // next region.
  689.     if ((y <= thisRegionTop) || (y >= nextRegionBottom))
  690.     return;
  691.  
  692.     dividedObject->EraseLinks(dc);
  693.  
  694.     // Now calculate the new proportions of this region and the next region.
  695.     double thisProportion = (double)((y - thisRegionTop)/dividedObject->GetHeight());
  696.     double nextProportion = (double)((nextRegionBottom - y)/dividedObject->GetHeight());
  697.     thisRegion->SetProportions(0.0, thisProportion);
  698.     nextRegion->SetProportions(0.0, nextProportion);
  699.     m_yoffset = (double)(y - dividedObject->GetY());
  700.  
  701.     // Now reformat text
  702.     int i = 0;
  703.     node = dividedObject->GetRegions().First();
  704.     while (node)
  705.     {
  706.         wxShapeRegion *region = (wxShapeRegion *)node->Data();
  707.         if (region->GetText())
  708.         {
  709.         wxChar *s = copystring(region->GetText());
  710.         dividedObject->FormatText(dc, s, i);
  711.         delete[] s;
  712.         }
  713.         node = node->Next();
  714.         i++;
  715.     }
  716.     dividedObject->SetRegionSizes();
  717.     dividedObject->Draw(dc);
  718.     dividedObject->GetEventHandler()->OnMoveLinks(dc);
  719. }
  720.  
  721.