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 / samples / ogl / studio / shapes.cpp < prev    next >
C/C++ Source or Header  |  2001-11-19  |  36KB  |  1,195 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        shapes.cpp
  3. // Purpose:     Implements Studio shapes
  4. // Author:      Julian Smart
  5. // Modified by:
  6. // Created:     12/07/98
  7. // RCS-ID:      $Id: shapes.cpp,v 1.3 2001/11/19 16:07:18 JS Exp $
  8. // Copyright:   (c) Julian Smart
  9. // Licence:       wxWindows licence
  10. /////////////////////////////////////////////////////////////////////////////
  11.  
  12. #ifdef __GNUG__
  13. // #pragma implementation
  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. #if !wxUSE_DOC_VIEW_ARCHITECTURE
  28. #error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in wx_setup.h!
  29. #endif
  30.  
  31. #include <wx/wxexpr.h>
  32.  
  33. #include "studio.h"
  34. #include "doc.h"
  35. #include "shapes.h"
  36. #include "view.h"
  37. #include <wx/ogl/basicp.h>
  38. #include <wx/ogl/linesp.h>
  39. #include "cspalette.h"
  40. #include "dialogs.h"
  41.  
  42. #define csSTANDARD_SHAPE_WIDTH      100
  43.  
  44. IMPLEMENT_CLASS(csDiagram, wxDiagram)
  45.  
  46. csDiagram::~csDiagram()
  47. {
  48.     DeleteAllShapes();
  49. }
  50.  
  51. void csDiagram::Redraw(wxDC& dc)
  52. {
  53.     wxDiagram::Redraw(dc);
  54.  
  55.     // Draw line crossings
  56.     wxLineCrossings lineCrossings;
  57.     lineCrossings.FindCrossings(*this);
  58.     lineCrossings.DrawCrossings(*this, dc);
  59. }
  60.  
  61. /*
  62.  * csEvtHandler: an event handler class for all shapes
  63.  */
  64.  
  65. IMPLEMENT_DYNAMIC_CLASS(csEvtHandler, wxShapeEvtHandler)
  66.  
  67. csEvtHandler::csEvtHandler(wxShapeEvtHandler *prev, wxShape *shape, const wxString& lab):
  68.   wxShapeEvtHandler(prev, shape)
  69. {
  70.     m_label = lab;
  71. }
  72.  
  73. csEvtHandler::~csEvtHandler()
  74. {
  75. }
  76.  
  77. // Copy any event handler data
  78. void csEvtHandler::CopyData(wxShapeEvtHandler& copy)
  79. {
  80.     wxShapeEvtHandler::CopyData(copy);
  81.  
  82.     csEvtHandler& csCopy = (csEvtHandler&) copy;
  83.     csCopy.m_label = m_label;
  84. }
  85.  
  86. void csEvtHandler::OnLeftClick(double x, double y, int keys, int attachment)
  87. {
  88.   wxClientDC dc(GetShape()->GetCanvas());
  89.   GetShape()->GetCanvas()->PrepareDC(dc);
  90.  
  91.   csDiagramView* view = ((csCanvas*)GetShape()->GetCanvas())->GetView();
  92.   view->ReflectPointSize(GetShape()->GetFont()->GetPointSize());
  93.  
  94.   if (GetShape()->IsKindOf(CLASSINFO(wxLineShape)))
  95.       view->ReflectArrowState((wxLineShape*) GetShape());
  96.  
  97.   csEditorToolPalette *palette = wxGetApp().GetDiagramPalette();
  98.   if (palette->GetSelection() == PALETTE_TEXT_TOOL)
  99.   {
  100.         view->ReflectPointSize(GetShape()->GetFont()->GetPointSize());
  101.  
  102.         EditProperties();
  103. #if 0
  104.         csLabelEditingDialog* dialog = new csLabelEditingDialog(GetShape()->GetCanvas()->GetParent());
  105.         dialog->SetShapeLabel(m_label);
  106.         if (dialog->ShowModal() == wxID_CANCEL)
  107.         {
  108.             dialog->Destroy();
  109.             return;
  110.         }
  111.  
  112.         wxString newLabel = dialog->GetShapeLabel();
  113.         dialog->Destroy();
  114.  
  115.         wxShape* newShape = GetShape()->CreateNewCopy();
  116.  
  117.         csEvtHandler* handler = (csEvtHandler *)newShape->GetEventHandler();
  118.         handler->m_label = newLabel;
  119.  
  120.         view->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Edit label", (csDiagramDocument*) view->GetDocument(),
  121.             new csCommandState(ID_CS_EDIT_PROPERTIES, newShape, GetShape())));
  122. #endif
  123.         return;
  124.   }
  125.  
  126.   if (keys == 0)
  127.   {
  128.     // If no shift key, then everything is deselected.
  129.     // If the shape was selected, deselect it and vice versa.
  130.     bool selected = GetShape()->Selected();
  131.  
  132.     view->SelectAll(FALSE);
  133.  
  134.     selected = !selected;
  135.  
  136.     GetShape()->Select(selected, &dc);
  137.     GetShape()->GetCanvas()->Redraw(dc); // Redraw because bits of objects will be missing
  138.  
  139.     view->SelectShape(GetShape(), selected);
  140.   }
  141.   else if (keys & KEY_SHIFT)
  142.   {
  143.     if (GetShape()->Selected())
  144.     {
  145.         GetShape()->Select(FALSE, &dc);
  146.         view->SelectShape(GetShape(), FALSE);
  147.     }
  148.     else
  149.     {
  150.         GetShape()->Select(TRUE, &dc);
  151.         view->SelectShape(GetShape(), TRUE);
  152.     }
  153.     GetShape()->GetCanvas()->Redraw(dc); // Redraw because bits of objects will be missing
  154.   }
  155.   else if (keys & KEY_CTRL)
  156.   {
  157.     // Do something for CONTROL
  158.   }
  159.   else
  160.   {
  161.     ((wxFrame*)wxGetApp().GetTopWindow())->SetStatusText(m_label);
  162.   }
  163. }
  164.  
  165. void csEvtHandler::OnRightClick(double x, double y, int keys, int attachment)
  166. {
  167.     // Have to convert back to physical coordinates from logical coordinates.
  168.  
  169.     int viewStartX, viewStartY;
  170.     int unitX, unitY;
  171.     GetShape()->GetCanvas()->GetViewStart(& viewStartX, & viewStartY);
  172.     GetShape()->GetCanvas()->GetScrollPixelsPerUnit(& unitX, & unitY);
  173.  
  174.     int x1 = (int)(x * GetShape()->GetCanvas()->GetScaleX());
  175.     int y1 = (int)(y * GetShape()->GetCanvas()->GetScaleY());
  176.  
  177.     int menuX = (int) (x1 - (viewStartX * unitX)) ;
  178.     int menuY = (int) (y1 - (viewStartY * unitY));
  179.  
  180.     wxGetApp().GetShapeEditMenu()->SetClientData((char*) GetShape());
  181.     wxGetApp().GetShapeEditMenu()->Enable(ID_CS_ROTATE_CLOCKWISE, !GetShape()->IsKindOf(CLASSINFO(wxLineShape)));
  182.     wxGetApp().GetShapeEditMenu()->Enable(ID_CS_ROTATE_ANTICLOCKWISE, !GetShape()->IsKindOf(CLASSINFO(wxLineShape)));
  183.  
  184.     GetShape()->GetCanvas()->PopupMenu(wxGetApp().GetShapeEditMenu(), menuX, menuY);
  185. }
  186.  
  187. /*
  188.  * Implement connection of two shapes by right-dragging between them.
  189.  */
  190.  
  191. void csEvtHandler::OnBeginDragRight(double x, double y, int keys, int attachment)
  192. {
  193.   wxClientDC dc(GetShape()->GetCanvas());
  194.   GetShape()->GetCanvas()->PrepareDC(dc);
  195.  
  196.   wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
  197.   dc.SetLogicalFunction(OGLRBLF);
  198.   dc.SetPen(dottedPen);
  199.   double xp, yp;
  200.   GetShape()->GetAttachmentPositionEdge(attachment, &xp, &yp);
  201.   dc.DrawLine(xp, yp, x, y);
  202.   GetShape()->GetCanvas()->CaptureMouse();
  203. }
  204.  
  205. void csEvtHandler::OnDragRight(bool draw, double x, double y, int keys, int attachment)
  206. {
  207.   wxClientDC dc(GetShape()->GetCanvas());
  208.   GetShape()->GetCanvas()->PrepareDC(dc);
  209.  
  210.   wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
  211.   dc.SetLogicalFunction(OGLRBLF);
  212.   dc.SetPen(dottedPen);
  213.   double xp, yp;
  214.   GetShape()->GetAttachmentPositionEdge(attachment, &xp, &yp);
  215.   dc.DrawLine(xp, yp, x, y);
  216. }
  217.  
  218. void csEvtHandler::OnEndDragRight(double x, double y, int keys, int attachment)
  219. {
  220.   GetShape()->GetCanvas()->ReleaseMouse();
  221.   csCanvas *canvas = (csCanvas *)GetShape()->GetCanvas();
  222.  
  223.   // Check if we're on an object
  224.   int new_attachment;
  225.   wxShape *otherShape = canvas->FindFirstSensitiveShape(x, y, &new_attachment, OP_DRAG_RIGHT);
  226.   
  227.   if (otherShape && !otherShape->IsKindOf(CLASSINFO(wxLineShape)))
  228.   {
  229.         wxLineShape* theShape = new csLineShape;
  230.  
  231.         theShape->AssignNewIds();
  232.         theShape->SetEventHandler(new csEvtHandler(theShape, theShape, wxString("")));
  233.         theShape->SetPen(wxBLACK_PEN);
  234.         theShape->SetBrush(wxRED_BRUSH);
  235.  
  236.         wxToolBar* toolbar = wxGetApp().GetDiagramToolBar();
  237.         bool haveArrow = toolbar->GetToolState(DIAGRAM_TOOLBAR_LINE_ARROW);
  238.  
  239.         wxLineShape *lineShape = (wxLineShape *)theShape;
  240.  
  241.         // Yes, you can have more than 2 control points, in which case
  242.         // it becomes a multi-segment line.
  243.         lineShape->MakeLineControlPoints(2);
  244.  
  245.         if (haveArrow)
  246.             lineShape->AddArrow(ARROW_ARROW, ARROW_POSITION_MIDDLE, 10.0, 0.0, "Normal arrowhead");
  247.  
  248.         lineShape->SetFrom(GetShape());
  249.         lineShape->SetTo(otherShape);
  250.         lineShape->SetAttachments(attachment, new_attachment);
  251.  
  252.         canvas->GetView()->GetDocument()->GetCommandProcessor()->Submit(
  253.             new csDiagramCommand("Line", (csDiagramDocument *)canvas->GetView()->GetDocument(),
  254.                     new csCommandState(ID_CS_ADD_LINE, lineShape, NULL)));
  255.   }
  256. }
  257.  
  258. static double g_DragOffsetX = 0.0;
  259. static double g_DragOffsetY = 0.0;
  260. static double g_DragStartX = 0.0;
  261. static double g_DragStartY = 0.0;
  262.  
  263. void csEvtHandler::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
  264. {
  265.   if ((GetShape()->GetSensitivityFilter() & OP_DRAG_LEFT) != OP_DRAG_LEFT)
  266.   {
  267.     attachment = 0;
  268.     double dist;
  269.     if (GetShape()->GetParent())
  270.     {
  271.       GetShape()->GetParent()->HitTest(x, y, &attachment, &dist);
  272.       GetShape()->GetParent()->GetEventHandler()->OnDragLeft(draw, x, y, keys, attachment);
  273.     }
  274.     return;
  275.   }
  276.  
  277.   wxClientDC dc(GetShape()->GetCanvas());
  278.   GetShape()->GetCanvas()->PrepareDC(dc);
  279.  
  280.   dc.SetLogicalFunction(OGLRBLF);
  281.  
  282.   wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
  283.   dc.SetPen(dottedPen);
  284.   dc.SetBrush(* wxTRANSPARENT_BRUSH);
  285.  
  286.   double xx, yy;
  287.   xx = x + g_DragOffsetX;
  288.   yy = y + g_DragOffsetY;
  289.  
  290.   GetShape()->GetCanvas()->Snap(&xx, &yy);
  291.  
  292.   double offsetX = xx - g_DragStartX;
  293.   double offsetY = yy - g_DragStartY;
  294.  
  295. //  m_xpos = xx; m_ypos = yy;
  296.   double w, h;
  297.   GetShape()->GetBoundingBoxMax(&w, &h);
  298.   GetShape()->GetEventHandler()->OnDrawOutline(dc, xx, yy, w, h);
  299.  
  300.   // Draw bounding box for other selected shapes
  301.   wxNode* node = GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->First();
  302.   while (node)
  303.   {
  304.      wxShape* shape = (wxShape*) node->Data();
  305.      if (shape->Selected() && !shape->IsKindOf(CLASSINFO(wxLineShape)) && (shape != GetShape()))
  306.      {
  307.         shape->GetBoundingBoxMax(&w, &h);
  308.         shape->OnDrawOutline(dc, shape->GetX() + offsetX, shape->GetY() + offsetY, w, h);
  309.      }
  310.      node = node->Next();
  311.   }
  312. }
  313.  
  314. void csEvtHandler::OnBeginDragLeft(double x, double y, int keys, int attachment)
  315. {
  316.   if ((GetShape()->GetSensitivityFilter() & OP_DRAG_LEFT) != OP_DRAG_LEFT)
  317.   {
  318.     attachment = 0;
  319.     double dist;
  320.     if (GetShape()->GetParent())
  321.     {
  322.       GetShape()->GetParent()->HitTest(x, y, &attachment, &dist);
  323.       GetShape()->GetParent()->GetEventHandler()->OnBeginDragLeft(x, y, keys, attachment);
  324.     }
  325.     return;
  326.   }
  327.  
  328.   wxClientDC dc(GetShape()->GetCanvas());
  329.   GetShape()->GetCanvas()->PrepareDC(dc);
  330.  
  331.   // New policy: don't erase shape until end of drag.
  332. //  Erase(dc);
  333.  
  334.   g_DragOffsetX = GetShape()->GetX() - x;
  335.   g_DragOffsetY = GetShape()->GetY() - y;
  336.  
  337.   double xx, yy;
  338.   xx = x + g_DragOffsetX;
  339.   yy = y + g_DragOffsetY;
  340.  
  341.   GetShape()->GetCanvas()->Snap(&xx, &yy);
  342.  
  343.   g_DragStartX = GetShape()->GetX();
  344.   g_DragStartY = GetShape()->GetY();
  345.  
  346.   double offsetX = xx - g_DragStartX;
  347.   double offsetY = yy - g_DragStartY;
  348.  
  349.   dc.SetLogicalFunction(OGLRBLF);
  350.  
  351.   wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
  352.   dc.SetPen(dottedPen);
  353.   dc.SetBrush((* wxTRANSPARENT_BRUSH));
  354.  
  355.   double w, h;
  356.   GetShape()->GetBoundingBoxMax(&w, &h);
  357.   GetShape()->GetEventHandler()->OnDrawOutline(dc, xx, yy, w, h);
  358.  
  359.   // Draw bounding box for other selected shapes
  360.   wxNode* node = GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->First();
  361.   while (node)
  362.   {
  363.      wxShape* shape = (wxShape*) node->Data();
  364.      if (shape->Selected() && !shape->IsKindOf(CLASSINFO(wxLineShape)) && (shape != GetShape()))
  365.      {
  366.         shape->GetBoundingBoxMax(&w, &h);
  367.         shape->OnDrawOutline(dc, shape->GetX() + offsetX, shape->GetY() + offsetY, w, h);
  368.      }
  369.      node = node->Next();
  370.   }
  371.  
  372.   GetShape()->GetCanvas()->CaptureMouse();
  373. }
  374.  
  375.  
  376. void csEvtHandler::OnEndDragLeft(double x, double y, int keys, int attachment)
  377. {
  378.   csCanvas *canvas = (csCanvas *)GetShape()->GetCanvas();
  379.  
  380.   canvas->ReleaseMouse();
  381.   if ((GetShape()->GetSensitivityFilter() & OP_DRAG_LEFT) != OP_DRAG_LEFT)
  382.   {
  383.     attachment = 0;
  384.     double dist;
  385.     if (GetShape()->GetParent())
  386.     {
  387.       GetShape()->GetParent()->HitTest(x, y, &attachment, &dist);
  388.       GetShape()->GetParent()->GetEventHandler()->OnEndDragLeft(x, y, keys, attachment);
  389.     }
  390.     return;
  391.   }
  392.  
  393.   wxClientDC dc(canvas);
  394.   canvas->PrepareDC(dc);
  395.  
  396.   dc.SetLogicalFunction(wxCOPY);
  397.  
  398.   double xx = x + g_DragOffsetX;
  399.   double yy = y + g_DragOffsetY;
  400.  
  401.   canvas->Snap(&xx, &yy);
  402.  
  403.   double offsetX = xx - g_DragStartX;
  404.   double offsetY = yy - g_DragStartY;
  405.  
  406.   wxShape* newShape = GetShape()->CreateNewCopy();
  407.  
  408.   newShape->SetX(xx);
  409.   newShape->SetY(yy);
  410.  
  411.   csDiagramCommand* cmd = new csDiagramCommand("Move", (csDiagramDocument*)canvas->GetView()->GetDocument(),
  412.                 new csCommandState(ID_CS_MOVE, newShape, GetShape()));
  413.  
  414.   // Move line points
  415.   wxNode* node = GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->First();
  416.   while (node)
  417.   {
  418.      wxShape* shape = (wxShape*) node->Data();
  419.      // Only move the line point(s) if both ends move too
  420.      if (shape->IsKindOf(CLASSINFO(wxLineShape)) &&
  421.            ((wxLineShape*)shape)->GetTo()->Selected() && ((wxLineShape*)shape)->GetFrom()->Selected())
  422.      {
  423.         wxLineShape* lineShape = (wxLineShape*) shape;
  424.  
  425.         if (lineShape->GetLineControlPoints()->Number() > 2)
  426.         {
  427.             wxLineShape* newLineShape = (wxLineShape*) lineShape->CreateNewCopy();
  428.  
  429.             wxNode *node1 = newLineShape->GetLineControlPoints()->First();
  430.             while (node1)
  431.             {
  432.                 wxRealPoint *point = (wxRealPoint *)node1->Data();
  433.                 point->x += offsetX;
  434.                 point->y += offsetY;
  435.                 node1 = node1->Next();
  436.             }
  437.             cmd->AddState(new csCommandState(ID_CS_MOVE_LINE_POINT, newLineShape, lineShape));
  438.             lineShape->Erase(dc);
  439.         }
  440.      }
  441.      node = node->Next();
  442.   }
  443.  
  444.   // Add other selected node shapes, if any
  445.   node = GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->First();
  446.   while (node)
  447.   {
  448.      wxShape* shape = (wxShape*) node->Data();
  449.      if (shape->Selected() && !shape->IsKindOf(CLASSINFO(wxLineShape)) && (shape != GetShape()))
  450.      {
  451.         wxShape* newShape2 = shape->CreateNewCopy();
  452.         newShape2->SetX(shape->GetX() + offsetX);
  453.         newShape2->SetY(shape->GetY() + offsetY);
  454.         cmd->AddState(new csCommandState(ID_CS_MOVE, newShape2, shape));
  455.      }
  456.      node = node->Next();
  457.   }
  458.  
  459.   canvas->GetView()->GetDocument()->GetCommandProcessor()->Submit(cmd);
  460. }
  461.  
  462. void csEvtHandler::OnSizingEndDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment)
  463. {
  464.   wxShape* shape = GetShape();
  465.   csCanvas *canvas = (csCanvas *)GetShape()->GetCanvas();
  466.  
  467.   if (shape->IsKindOf(CLASSINFO(wxLineShape)))
  468.   {
  469.     // TODO: Do/Undo support for line operations
  470.     ((wxLineShape*)shape)->wxLineShape::OnSizingEndDragLeft(pt, x, y, keys, attachment);
  471. #if 0
  472.         wxLineShape* lineShape = (wxLineShape*) shape;
  473.  
  474.         wxLineControlPoint* lpt = (wxLineControlPoint*) pt;
  475.  
  476.         wxClientDC dc(canvas);
  477.         canvas->PrepareDC(dc);
  478.  
  479.         shape->SetDisableLabel(FALSE);
  480.  
  481.         if (lpt->m_type == CONTROL_POINT_LINE)
  482.         {
  483.             canvas->Snap(&x, &y);
  484.  
  485.             dc.SetLogicalFunction(wxCOPY);
  486.             lpt->SetX(x); lpt->SetY(y);
  487.             lpt->m_point->x = x; lpt->m_point->y = y;
  488.  
  489.             this->OnMoveLink(dc);
  490.         }
  491.         if (lpt->m_type == CONTROL_POINT_ENDPOINT_FROM)
  492.         {
  493.             if (lpt->m_oldCursor)
  494.                 canvas->SetCursor(lpt->m_oldCursor);
  495.             lineShape->Erase(dc);
  496.  
  497.             lpt->SetX(x); lpt->SetY(y);
  498.  
  499.             if (lineShape->GetFrom())
  500.             {
  501.                 lineShape->GetFrom()->MoveLineToNewAttachment(dc, lineShape, x, y);
  502.             }
  503.         }
  504.         if (lpt->m_type == CONTROL_POINT_ENDPOINT_TO)
  505.         {
  506.             if (lpt->m_oldCursor)
  507.                 canvas->SetCursor(lpt->m_oldCursor);
  508.  
  509.             lpt->SetX(x); lpt->SetY(y);
  510.  
  511.             if (lineShape->GetTo())
  512.             {
  513.                 lineShape->GetTo()->MoveLineToNewAttachment(dc, lineShape, x, y);
  514.             }
  515.         }
  516. #endif
  517.         return;
  518.   }
  519.  
  520.   wxClientDC dc(canvas);
  521.   canvas->PrepareDC(dc);
  522.  
  523.   canvas->ReleaseMouse();
  524.   dc.SetLogicalFunction(wxCOPY);
  525.  
  526. //  shape->Erase(dc);
  527. /*
  528.   shape->Recompute();
  529.   shape->ResetControlPoints();
  530.   if (!pt->m_eraseObject)
  531.     shape->Show(FALSE);
  532. */
  533.  
  534.   wxShape* newShape = shape->CreateNewCopy();
  535.  
  536.   if (newShape->IsKindOf(CLASSINFO(wxPolygonShape)))
  537.   {
  538.     wxPolygonControlPoint* ppt = (wxPolygonControlPoint*) pt;
  539.     newShape->SetSize(ppt->GetNewSize().x, ppt->GetNewSize().y);
  540.  
  541.     ((wxPolygonShape *)newShape)->CalculateBoundingBox();
  542.     ((wxPolygonShape *)newShape)->CalculatePolygonCentre();
  543.     newShape->ResetControlPoints();
  544.   }
  545.   else
  546.   {
  547.     newShape->SetSize(pt->sm_controlPointDragEndWidth, pt->sm_controlPointDragEndHeight);
  548.     if (shape->GetCentreResize())
  549.     {
  550.       // Old position is fine
  551.     }
  552.     else
  553.     {
  554.       newShape->SetX(pt->sm_controlPointDragPosX);
  555.       newShape->SetY(pt->sm_controlPointDragPosY);
  556.     }
  557.   }
  558.  
  559.   csDiagramCommand* cmd = new csDiagramCommand("Size", (csDiagramDocument*)canvas->GetView()->GetDocument(),
  560.                 new csCommandState(ID_CS_SIZE, newShape, shape));
  561.  
  562.   canvas->GetView()->GetDocument()->GetCommandProcessor()->Submit(cmd);
  563.  
  564. }
  565.  
  566. void csEvtHandler::OnEndSize(double x, double y)
  567. {
  568.   wxClientDC dc(GetShape()->GetCanvas());
  569.   GetShape()->GetCanvas()->PrepareDC(dc);
  570.  
  571.   GetShape()->FormatText(dc, m_label);
  572. }
  573.  
  574. void csEvtHandler::OnChangeAttachment(int attachment, wxLineShape* line, wxList& ordering)
  575. {
  576.     csCanvas *canvas = (csCanvas *)GetShape()->GetCanvas();
  577.  
  578.     // We actually submit two different states: one to change the ordering, and another
  579.     // to change the attachment for the line.
  580.     // Problem. If we refresh after the attachment change, we'll get a flicker.
  581.     // We really want to do both in a oner.
  582.  
  583.     csDiagramCommand* cmd = new csDiagramCommand("Change attachment", (csDiagramDocument*)canvas->GetView()->GetDocument());
  584.  
  585.     wxLineShape* newLine = (wxLineShape*) line->CreateNewCopy();
  586.     if (line->GetTo() == GetShape())
  587.         newLine->SetAttachmentTo(attachment);
  588.     else
  589.         newLine->SetAttachmentFrom(attachment);
  590.  
  591.     cmd->AddState(new csCommandState(ID_CS_CHANGE_LINE_ATTACHMENT, newLine, line));
  592.  
  593.     // Change ordering
  594.     wxShape* newShape = GetShape()->CreateNewCopy();
  595.     newShape->ApplyAttachmentOrdering(ordering);
  596.  
  597.     cmd->AddState(new csCommandState(ID_CS_CHANGE_LINE_ORDERING, newShape, GetShape()));
  598.  
  599.     canvas->GetView()->GetDocument()->GetCommandProcessor()->Submit(cmd);
  600. }
  601.  
  602. void csEvtHandler::OnLeftDoubleClick(double x, double y, int keys, int attachment)
  603. {
  604.     EditProperties();
  605. }
  606.  
  607. // Popup up a property dialog
  608. bool csEvtHandler::EditProperties()
  609. {
  610.     wxShape* shape = GetShape();
  611.  
  612.     // For now, no line property editing
  613.     if (shape->IsKindOf(CLASSINFO(wxLineShape)))
  614.         return FALSE;
  615.  
  616.     csDiagramView* view = ((csCanvas*)shape->GetCanvas())->GetView();
  617.  
  618.     wxPanel* attributeDialog;
  619.     wxString attributeDialogName;
  620.     wxString title;
  621.  
  622.     if (shape->IsKindOf(CLASSINFO(csThinRectangleShape)))
  623.     {
  624.         attributeDialog = new csThinRectangleDialog;
  625.         attributeDialogName = "thin_rectangle";
  626.         title = "Thin Rectangle Properties";
  627.     }
  628.     else if (shape->IsKindOf(CLASSINFO(csWideRectangleShape)))
  629.     {
  630.         attributeDialog = new csWideRectangleDialog;
  631.         attributeDialogName = "wide_rectangle";
  632.         title = "Wide Rectangle Properties";
  633.     }
  634.     else if (shape->IsKindOf(CLASSINFO(csTriangleShape)))
  635.     {
  636.         attributeDialog = new csTriangleDialog;
  637.         attributeDialogName = "triangle";
  638.         title = "Triangle Properties";
  639.     }
  640.     else if (shape->IsKindOf(CLASSINFO(csSemiCircleShape)))
  641.     {
  642.         attributeDialog = new csSemiCircleDialog;
  643.         attributeDialogName = "semi_circle";
  644.         title = "Semicircle Properties";
  645.     }
  646.     else if (shape->IsKindOf(CLASSINFO(csCircleShape)))
  647.     {
  648.         attributeDialog = new csCircleDialog;
  649.         attributeDialogName = "circle";
  650.         title = "Circle Properties";
  651.     }
  652.     else if (shape->IsKindOf(CLASSINFO(csCircleShadowShape)))
  653.     {
  654.         attributeDialog = new csCircleShadowDialog;
  655.         attributeDialogName = "circle_shadow";
  656.         title = "Circle Shadow Properties";
  657.     }
  658.     else if (shape->IsKindOf(CLASSINFO(csTextBoxShape)))
  659.     {
  660.         attributeDialog = new csTextBoxDialog;
  661.         attributeDialogName = "text_box";
  662.         title = "Text Box Properties";
  663.     }
  664.     else if (shape->IsKindOf(CLASSINFO(csGroupShape)))
  665.     {
  666.         attributeDialog = new csGroupDialog;
  667.         attributeDialogName = "group";
  668.         title = "Group Properties";
  669.     }
  670.     else if (shape->IsKindOf(CLASSINFO(csOctagonShape)))
  671.     {
  672.         attributeDialog = new csOctagonDialog;
  673.         attributeDialogName = "octagon";
  674.         title = "Octagon Properties";
  675.     }
  676.     else
  677.     {
  678.         wxMessageBox("Unrecognised shape.", "Studio", wxICON_EXCLAMATION);
  679.         return FALSE;
  680.     }
  681.  
  682.     csShapePropertiesDialog* dialog = new csShapePropertiesDialog(shape->GetCanvas()->GetParent(), title, attributeDialog, attributeDialogName);
  683.     dialog->GetGeneralPropertiesDialog()->SetShapeLabel(m_label);
  684.     if (dialog->ShowModal() == wxID_CANCEL)
  685.     {
  686.         dialog->Destroy();
  687.         return FALSE;
  688.     }
  689.  
  690.     wxString newLabel = dialog->GetGeneralPropertiesDialog()->GetShapeLabel();
  691.     dialog->Destroy();
  692.  
  693.     wxShape* newShape = shape->CreateNewCopy();
  694.  
  695.     csEvtHandler* handler2 = (csEvtHandler *)newShape->GetEventHandler();
  696.     handler2->m_label = newLabel;
  697.  
  698.     view->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Edit properties", (csDiagramDocument*) view->GetDocument(),
  699.                 new csCommandState(ID_CS_EDIT_PROPERTIES, newShape, shape)));
  700.  
  701.     return TRUE;
  702. }
  703.  
  704. /*
  705.  * Diagram
  706.  */
  707.  
  708. bool csDiagram::OnShapeSave(wxExprDatabase& db, wxShape& shape, wxExpr& expr)
  709. {
  710.   wxDiagram::OnShapeSave(db, shape, expr);
  711.   csEvtHandler *handler = (csEvtHandler *)shape.GetEventHandler();
  712.   expr.AddAttributeValueString("label", handler->m_label);
  713.   return TRUE;
  714. }
  715.  
  716. bool csDiagram::OnShapeLoad(wxExprDatabase& db, wxShape& shape, wxExpr& expr)
  717. {
  718.   wxDiagram::OnShapeLoad(db, shape, expr);
  719.   wxString label("");
  720.   expr.GetAttributeValue("label", label);
  721.   csEvtHandler *handler = new csEvtHandler(&shape, &shape, label);
  722.   shape.SetEventHandler(handler);
  723.   
  724.   return TRUE;
  725. }
  726.  
  727. IMPLEMENT_DYNAMIC_CLASS(csThinRectangleShape, wxDrawnShape)
  728.  
  729. csThinRectangleShape::csThinRectangleShape()
  730. {
  731.     SetDrawnPen(wxBLACK_PEN);
  732.     wxBrush* brush = wxTheBrushList->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID);
  733.     SetDrawnBrush(brush);
  734.  
  735.     double w = csSTANDARD_SHAPE_WIDTH/2;
  736.     double h = csSTANDARD_SHAPE_WIDTH;
  737.  
  738.     DrawRectangle(wxRect(- w/2, - h/2, w, h));
  739.     CalculateSize();
  740.  
  741.     SetAttachmentMode(ATTACHMENT_MODE_BRANCHING);
  742.     SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
  743.     SetCentreResize(FALSE);
  744. }
  745.  
  746. IMPLEMENT_DYNAMIC_CLASS(csWideRectangleShape, wxDrawnShape)
  747.  
  748. csWideRectangleShape::csWideRectangleShape()
  749. {
  750.     SetDrawnPen(wxBLACK_PEN);
  751.     wxBrush* brush = wxTheBrushList->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID);
  752.     SetDrawnBrush(brush);
  753.  
  754.     double w = csSTANDARD_SHAPE_WIDTH;
  755.     double h = w/2.0;
  756.  
  757.     DrawRoundedRectangle(wxRect(- w/2, - h/2, w, h), -0.3);
  758.     CalculateSize();
  759.  
  760.     SetAttachmentMode(ATTACHMENT_MODE_BRANCHING);
  761.     SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
  762.     SetCentreResize(FALSE);
  763. }
  764.  
  765. IMPLEMENT_DYNAMIC_CLASS(csTriangleShape, wxDrawnShape)
  766.  
  767. csTriangleShape::csTriangleShape()
  768. {
  769.     SetDrawnPen(wxBLACK_PEN);
  770.     wxBrush* brush = wxTheBrushList->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID);
  771.     SetDrawnBrush(brush);
  772.  
  773.     double w = csSTANDARD_SHAPE_WIDTH;
  774.     double h = (csSTANDARD_SHAPE_WIDTH*2.0)/3.0;
  775.  
  776.     // Triangle, from top vertex
  777.     wxPoint* points = new wxPoint[3];
  778.  
  779.  
  780.     points[0] = wxPoint( 0 ,  - h / 2 );
  781.     points[1] = wxPoint( w / 2 ,  h / 2 );
  782.     points[2] = wxPoint( -w / 2,  h / 2 );
  783.  
  784.     DrawPolygon(3, points, oglMETAFLAGS_OUTLINE);
  785.  
  786.     delete[] points;
  787.  
  788.     // Add another triangle at the top for the black bit
  789.     SetDrawnBrush(wxBLACK_BRUSH);
  790.  
  791.     points = new wxPoint[3];
  792.  
  793.     // Calculate where the new points will be, using the proportions
  794.     // of the triangle.
  795.     double h1 = 8; // Height of little triangle.
  796.  
  797.     /*
  798.         Formula: ((w/2) / h) = w1 / h1
  799.         w1 = ((w/2) / h) * h1;
  800.     */
  801.     double ratio = ((w/2.0) / h) ;
  802.     double w1 = ratio * h1;
  803.  
  804.     points[0] = wxPoint(0  ,  (int) (- h / 2 ));
  805.     points[1] = wxPoint( (int) w1,  (int) (- h / 2 + h1));
  806.     points[2] = wxPoint( (int) -w1, (int) (- h / 2 + h1));
  807.  
  808.     DrawPolygon(3, points);
  809.  
  810.     delete[] points;
  811.  
  812.     CalculateSize();
  813.  
  814.     SetAttachmentMode(ATTACHMENT_MODE_BRANCHING);
  815.     SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
  816.     SetCentreResize(FALSE);
  817. }
  818.  
  819. IMPLEMENT_DYNAMIC_CLASS(csSemiCircleShape, wxDrawnShape)
  820.  
  821. csSemiCircleShape::csSemiCircleShape()
  822. {
  823.     // Zero degrees
  824.     DrawAtAngle(oglDRAWN_ANGLE_0);
  825.  
  826.     double w = csSTANDARD_SHAPE_WIDTH;
  827.     double h = w/2.0;
  828.  
  829.     SetDrawnPen(wxTRANSPARENT_PEN);
  830.     SetDrawnBrush(wxTRANSPARENT_BRUSH);
  831.  
  832.     // Draw a dummy rectangle that will be used for calculating the
  833.     // bounding box, since we can't calculate the bounding box for
  834.     // an arbitrary arc (not implemented)
  835.  
  836.     DrawRectangle(wxRect(-w/2.0, -h/2.0, w, h));
  837.  
  838.     SetDrawnPen(wxBLACK_PEN);
  839.     wxBrush* brush = wxTheBrushList->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID);
  840.     SetDrawnBrush(brush);
  841.  
  842.     DrawEllipticArc(wxRect(-w/2, -h/2, w, 2*h), 0.0, 180.0);
  843.     DrawLine(wxPoint(-w/2, h/2), wxPoint(w/2, h/2));
  844.  
  845.     CalculateSize();
  846.  
  847.     /// 90 degrees
  848.  
  849.     w = csSTANDARD_SHAPE_WIDTH/2;
  850.     h = csSTANDARD_SHAPE_WIDTH;
  851.  
  852.     DrawAtAngle(oglDRAWN_ANGLE_90);
  853.  
  854.     SetDrawnPen(wxTRANSPARENT_PEN);
  855.     SetDrawnBrush(wxTRANSPARENT_BRUSH);
  856.  
  857.     DrawRectangle(wxRect(-w/2, -h/2, w, h));
  858.  
  859.     SetDrawnPen(wxBLACK_PEN);
  860.     SetDrawnBrush(brush);
  861.  
  862.     DrawEllipticArc(wxRect(-w/2 - w, -h/2, 2*w, h), 270.0, 90.0);
  863.     DrawLine(wxPoint(-w/2, -h/2), wxPoint(-w/2, h/2));
  864.  
  865.     CalculateSize();
  866.  
  867.     /// 180 degrees
  868.  
  869.     DrawAtAngle(oglDRAWN_ANGLE_180);
  870.  
  871.     w = csSTANDARD_SHAPE_WIDTH;
  872.     h = csSTANDARD_SHAPE_WIDTH/2;
  873.  
  874.     SetDrawnPen(wxTRANSPARENT_PEN);
  875.     SetDrawnBrush(wxTRANSPARENT_BRUSH);
  876.  
  877.     DrawRectangle(wxRect(-w/2, -h/2, w, h));
  878.  
  879.     SetDrawnPen(wxBLACK_PEN);
  880.     SetDrawnBrush(brush);
  881.  
  882.     DrawEllipticArc(wxRect(-w/2, -h/2 - h, w, 2*h), 180.0, 0.0);
  883.     DrawLine(wxPoint(-w/2, -h/2), wxPoint(w/2, -h/2));
  884.  
  885.     CalculateSize();
  886.  
  887.     /// 270 degrees
  888.  
  889.     DrawAtAngle(oglDRAWN_ANGLE_270);
  890.  
  891.     w = csSTANDARD_SHAPE_WIDTH/2;
  892.     h = csSTANDARD_SHAPE_WIDTH;
  893.  
  894.     SetDrawnPen(wxTRANSPARENT_PEN);
  895.     SetDrawnBrush(wxTRANSPARENT_BRUSH);
  896.  
  897.     DrawRectangle(wxRect(-w/2, -h/2, w, h));
  898.  
  899.     SetDrawnPen(wxBLACK_PEN);
  900.     SetDrawnBrush(brush);
  901.  
  902.     DrawEllipticArc(wxRect(-w/2, -h/2, 2*w, h), 90.0, 270.0);
  903.     DrawLine(wxPoint(w/2, -h/2), wxPoint(w/2, h/2));
  904.  
  905.     CalculateSize();
  906.  
  907.     // Reset to zero
  908.     DrawAtAngle(oglDRAWN_ANGLE_0);
  909.     CalculateSize();
  910.  
  911.     SetAttachmentMode(ATTACHMENT_MODE_BRANCHING);
  912.     SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
  913.     SetCentreResize(FALSE);
  914. }
  915.  
  916. IMPLEMENT_DYNAMIC_CLASS(csCircleShape, wxCircleShape)
  917.  
  918. csCircleShape::csCircleShape()
  919. {
  920.     SetPen(wxBLACK_PEN);
  921.     wxBrush* brush = wxTheBrushList->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID);
  922.     SetBrush(brush);
  923.  
  924.     SetSize(csSTANDARD_SHAPE_WIDTH*0.6, csSTANDARD_SHAPE_WIDTH*0.6);
  925.  
  926.     SetAttachmentMode(ATTACHMENT_MODE_BRANCHING);
  927.     SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
  928.     SetCentreResize(FALSE);
  929. }
  930.  
  931. IMPLEMENT_DYNAMIC_CLASS(csCircleShadowShape, wxCircleShape)
  932.  
  933. csCircleShadowShape::csCircleShadowShape()
  934. {
  935.     SetPen(wxBLACK_PEN);
  936.     wxBrush* brush = wxTheBrushList->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID);
  937.     SetBrush(brush);
  938.  
  939.     SetSize(csSTANDARD_SHAPE_WIDTH*0.6, csSTANDARD_SHAPE_WIDTH*0.6);
  940.  
  941.     SetAttachmentMode(ATTACHMENT_MODE_BRANCHING);
  942.     SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
  943.     SetCentreResize(FALSE);
  944.     SetShadowMode(SHADOW_RIGHT);
  945. }
  946.  
  947. IMPLEMENT_DYNAMIC_CLASS(csOctagonShape, wxPolygonShape)
  948.  
  949. csOctagonShape::csOctagonShape()
  950. {
  951.     SetPen(wxBLACK_PEN);
  952.     SetBrush(wxTheBrushList->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID));
  953.  
  954.     double w = csSTANDARD_SHAPE_WIDTH*0.5;
  955.     double h = csSTANDARD_SHAPE_WIDTH*0.5;
  956.  
  957.     double prop = h/3.0;
  958.  
  959.     wxList* points = new wxList;
  960.     points->Append((wxObject*) new wxRealPoint(-w/2.0 + prop, -h/2.0));
  961.     points->Append((wxObject*) new wxRealPoint(w/2.0 - prop, -h/2.0));
  962.     points->Append((wxObject*) new wxRealPoint(w/2.0, -h/2.0 + prop));
  963.     points->Append((wxObject*) new wxRealPoint(w/2.0, h/2.0 - prop));
  964.     points->Append((wxObject*) new wxRealPoint(w/2.0 - prop, h/2.0));
  965.     points->Append((wxObject*) new wxRealPoint(-w/2.0 + prop, h/2.0));
  966.     points->Append((wxObject*) new wxRealPoint(-w/2.0, h/2.0 - prop));
  967.     points->Append((wxObject*) new wxRealPoint(-w/2.0, -h/2.0 + prop));
  968.  
  969.     Create(points);
  970.  
  971.     SetAttachmentMode(ATTACHMENT_MODE_BRANCHING);
  972.     SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
  973.     SetCentreResize(FALSE);
  974. }
  975.  
  976. // This is a transparent shape for drawing around other shapes.
  977. IMPLEMENT_DYNAMIC_CLASS(csGroupShape, wxRectangleShape)
  978.  
  979. csGroupShape::csGroupShape()
  980. {
  981.     SetPen(wxThePenList->FindOrCreatePen("BLACK", 1, wxDOT));
  982.     SetBrush(wxTRANSPARENT_BRUSH);
  983.  
  984.     SetSize(csSTANDARD_SHAPE_WIDTH, csSTANDARD_SHAPE_WIDTH);
  985.     SetCentreResize(FALSE);
  986. }
  987.  
  988. void csGroupShape::OnDraw(wxDC& dc)
  989. {
  990.     wxRectangleShape::OnDraw(dc);
  991. }
  992.  
  993. // Must modify the hit-test so it doesn't obscure shapes that are inside.
  994. bool csGroupShape::HitTest(double x, double y, int* attachment, double* distance)
  995. {
  996.     *attachment = 0;
  997.     *distance = 0.0;
  998.  
  999.     double width = 0.0, height = 0.0;
  1000.     GetBoundingBoxMin(&width, &height);
  1001.  
  1002.     double x1 = GetX() - (width/2.0);
  1003.     double y1 = GetY() - (height/2.0);
  1004.     double x2 = GetX() + (width/2.0);
  1005.     double y2 = GetY() + (height/2.0);
  1006.  
  1007.     double edgeTolerance = 4.0;
  1008.  
  1009.     // Test each edge in turn
  1010.  
  1011.     // Top/bottom edges
  1012.     if (x >= x1 && x <= x2)
  1013.     {
  1014.         if ((y >= y1 - edgeTolerance) && (y <= y1 + edgeTolerance))
  1015.             return TRUE;
  1016.         if ((y <= y2 + edgeTolerance) && (y >= y2 - edgeTolerance))
  1017.             return TRUE;
  1018.     }
  1019.     // Left/right edges
  1020.     if (y >= y1 && y <= y2)
  1021.     {
  1022.         if ((x >= x1 - edgeTolerance) && (x <= x1 + edgeTolerance))
  1023.             return TRUE;
  1024.         if ((x <= x2 + edgeTolerance) && (x >= x2 - edgeTolerance))
  1025.             return TRUE;
  1026.     }
  1027.  
  1028.     return FALSE;
  1029. }
  1030.  
  1031. IMPLEMENT_DYNAMIC_CLASS(csTextBoxShape, wxRectangleShape)
  1032.  
  1033. csTextBoxShape::csTextBoxShape()
  1034. {
  1035.     SetPen(wxTRANSPARENT_PEN);
  1036.     SetBrush(wxTRANSPARENT_BRUSH);
  1037.  
  1038.     SetSize(csSTANDARD_SHAPE_WIDTH, csSTANDARD_SHAPE_WIDTH/2.0);
  1039.  
  1040.     SetAttachmentMode(ATTACHMENT_MODE_NONE);
  1041.     SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
  1042.     SetCentreResize(FALSE);
  1043. }
  1044.  
  1045. IMPLEMENT_DYNAMIC_CLASS(csLineShape, wxLineShape)
  1046.  
  1047. csLineShape::csLineShape()
  1048. {
  1049. }
  1050.  
  1051. bool csLineShape::OnMoveMiddleControlPoint(wxDC& dc, wxLineControlPoint* lpt, const wxRealPoint& pt)
  1052. {
  1053.     csDiagramView* view = ((csCanvas*)GetCanvas())->GetView();
  1054.  
  1055.     // Temporarily set the new shape properties so we can copy it
  1056.     lpt->SetX(pt.x); lpt->SetY(pt.y);
  1057.     lpt->m_point->x = pt.x; lpt->m_point->y = pt.y;
  1058.  
  1059.     wxLineShape* newShape = (wxLineShape*) this->CreateNewCopy();
  1060.  
  1061.     // Now set them back again
  1062.     lpt->SetX(lpt->m_originalPos.x); lpt->SetY(lpt->m_originalPos.y);
  1063.     lpt->m_point->x = lpt->m_originalPos.x; lpt->m_point->y = lpt->m_originalPos.y;
  1064.  
  1065.     view->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Move line point", (csDiagramDocument*) view->GetDocument(),
  1066.                 new csCommandState(ID_CS_MOVE_LINE_POINT, newShape, this)));
  1067.  
  1068.     return TRUE;
  1069. }
  1070.  
  1071. wxLabelShape* csLineShape::OnCreateLabelShape(wxLineShape *parent, wxShapeRegion *region, double w, double h)
  1072. {
  1073.     return new csLabelShape(parent, region, w, h);
  1074. }
  1075.  
  1076. #if 0
  1077. bool csLineShape::OnLabelMovePre(wxDC& dc, wxLabelShape* labelShape, double x, double y, double old_x, double old_y, bool display)
  1078. {
  1079.     csDiagramView* view = ((csCanvas*)GetCanvas())->GetView();
  1080.  
  1081.     wxLineShape* newShape = (wxLineShape*) this->CreateNewCopy();
  1082.  
  1083.     wxLineShape::OnLabelMovePre(dc, labelShape, x, y, old_x, old_y, display);
  1084.  
  1085.     view->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Move label", (csDiagramDocument*) view->GetDocument(),
  1086.                 new csCommandState(ID_CS_MOVE_LABEL, newShape, this)));
  1087.   return TRUE;
  1088. }
  1089. #endif
  1090.  
  1091. IMPLEMENT_DYNAMIC_CLASS(csLabelShape, wxLabelShape)
  1092.  
  1093. csLabelShape::csLabelShape(wxLineShape *parent, wxShapeRegion *region, double w, double h):
  1094.   wxLabelShape(parent, region, w, h)
  1095. {
  1096. }
  1097.  
  1098. // TODO: not sure how intercept normal behaviour (OnMovePre) to make
  1099. // label movement undo-able.
  1100. void csLabelShape::OnEndDragLeft(double x, double y, int keys, int attachment)
  1101. {
  1102.     wxLabelShape::OnEndDragLeft(x, y, keys, attachment);
  1103. }
  1104.  
  1105.  
  1106. // Menu for editing shapes
  1107. void studioShapeEditProc(wxMenu& menu, wxCommandEvent& event)
  1108. {
  1109.     wxShape* shape = (wxShape*) menu.GetClientData();
  1110.     csDiagramView* view = ((csCanvas*)shape->GetCanvas())->GetView();
  1111.  
  1112.     switch (event.GetId())
  1113.     {
  1114.         case ID_CS_EDIT_PROPERTIES:
  1115.         {
  1116.             csEvtHandler* handler1 = (csEvtHandler *)shape->GetEventHandler();
  1117.             handler1->EditProperties();
  1118. #if 0
  1119.             csEvtHandler* handler1 = (csEvtHandler *)shape->GetEventHandler();
  1120.             csLabelEditingDialog* dialog = new csLabelEditingDialog(shape->GetCanvas()->GetParent());
  1121.             dialog->SetShapeLabel(handler1->m_label);
  1122.             if (dialog->ShowModal() == wxID_CANCEL)
  1123.             {
  1124.                 dialog->Destroy();
  1125.                 return;
  1126.             }
  1127.  
  1128.             wxString newLabel = dialog->GetShapeLabel();
  1129.             dialog->Destroy();
  1130.  
  1131.             wxShape* newShape = shape->CreateNewCopy();
  1132.  
  1133.             csEvtHandler* handler2 = (csEvtHandler *)newShape->GetEventHandler();
  1134.             handler2->m_label = newLabel;
  1135.  
  1136.             view->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Edit label", (csDiagramDocument*) view->GetDocument(),
  1137.                 new csCommandState(ID_CS_EDIT_LABEL, newShape, shape)));
  1138. #endif
  1139.             break;
  1140.         }
  1141.         case wxID_CUT:
  1142.         {
  1143.             wxList list;
  1144.             list.Append(shape);
  1145.             view->DoCut(list);
  1146.             break;
  1147.         }
  1148.         case ID_CS_ROTATE_CLOCKWISE:
  1149.         case ID_CS_ROTATE_ANTICLOCKWISE:
  1150.         {
  1151.             if (shape->IsKindOf(CLASSINFO(wxLineShape)))
  1152.                 break;
  1153.  
  1154.             double theta = shape->GetRotation();
  1155.             const double myPi = 3.1415926535897932384626433832795 ;
  1156.             double ninetyDegrees = myPi/2.0;
  1157.  
  1158.             wxString opStr;
  1159.             if (event.GetId() == ID_CS_ROTATE_CLOCKWISE)
  1160.             {
  1161.                 theta += ninetyDegrees;
  1162.                 opStr = "Rotate clockwise";
  1163.             }
  1164.             else
  1165.             {
  1166.                 theta -= ninetyDegrees;
  1167.                 opStr = "Rotate anticlockwise";
  1168.             }
  1169.  
  1170.             if (theta >= 2.0*myPi || theta < 0.0)
  1171.                 theta = 0.0;
  1172.             wxShape* newShape = shape->CreateNewCopy();
  1173.             newShape->Rotate(0.0, 0.0, theta);
  1174.             wxList newShapes;
  1175.             wxList oldShapes;
  1176.             newShapes.Append(newShape);
  1177.             oldShapes.Append(shape);
  1178.             view->DoCmd(newShapes, oldShapes, event.GetId(), opStr);
  1179.             break;
  1180.         }
  1181.         default:
  1182.             break;
  1183.     }
  1184. }
  1185.  
  1186. BEGIN_EVENT_TABLE(ShapeEditMenu, wxMenu)
  1187.     EVT_COMMAND_RANGE(1, 65000, wxEVT_COMMAND_MENU_SELECTED, ShapeEditMenu::OnCommand)
  1188. END_EVENT_TABLE()
  1189.  
  1190. void ShapeEditMenu::OnCommand(wxCommandEvent& event)
  1191. {
  1192.     studioShapeEditProc(*this, event);
  1193. }
  1194.  
  1195.