git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@6407 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
		
			
				
	
	
		
			1195 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1195 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /////////////////////////////////////////////////////////////////////////////
 | |
| // Name:        shapes.cpp
 | |
| // Purpose:     Implements Studio shapes
 | |
| // Author:      Julian Smart
 | |
| // Modified by:
 | |
| // Created:     12/07/98
 | |
| // RCS-ID:      $Id$
 | |
| // Copyright:   (c) Julian Smart
 | |
| // Licence:   	wxWindows licence
 | |
| /////////////////////////////////////////////////////////////////////////////
 | |
| 
 | |
| #ifdef __GNUG__
 | |
| // #pragma implementation
 | |
| #endif
 | |
| 
 | |
| // For compilers that support precompilation, includes "wx.h".
 | |
| #include <wx/wxprec.h>
 | |
| 
 | |
| #ifdef __BORLANDC__
 | |
| #pragma hdrstop
 | |
| #endif
 | |
| 
 | |
| #ifndef WX_PRECOMP
 | |
| #include <wx/wx.h>
 | |
| #endif
 | |
| 
 | |
| #if !wxUSE_DOC_VIEW_ARCHITECTURE
 | |
| #error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in wx_setup.h!
 | |
| #endif
 | |
| 
 | |
| #include <wx/wxexpr.h>
 | |
| 
 | |
| #include "studio.h"
 | |
| #include "doc.h"
 | |
| #include "shapes.h"
 | |
| #include "view.h"
 | |
| #include <wx/ogl/basicp.h>
 | |
| #include <wx/ogl/linesp.h>
 | |
| #include "cspalette.h"
 | |
| #include "dialogs.h"
 | |
| 
 | |
| #define csSTANDARD_SHAPE_WIDTH      100
 | |
| 
 | |
| IMPLEMENT_CLASS(csDiagram, wxDiagram)
 | |
| 
 | |
| csDiagram::~csDiagram()
 | |
| {
 | |
|     DeleteAllShapes();
 | |
| }
 | |
| 
 | |
| void csDiagram::Redraw(wxDC& dc)
 | |
| {
 | |
|     wxDiagram::Redraw(dc);
 | |
| 
 | |
|     // Draw line crossings
 | |
|     wxLineCrossings lineCrossings;
 | |
|     lineCrossings.FindCrossings(*this);
 | |
|     lineCrossings.DrawCrossings(*this, dc);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * csEvtHandler: an event handler class for all shapes
 | |
|  */
 | |
| 
 | |
| IMPLEMENT_DYNAMIC_CLASS(csEvtHandler, wxShapeEvtHandler)
 | |
| 
 | |
| csEvtHandler::csEvtHandler(wxShapeEvtHandler *prev, wxShape *shape, const wxString& lab):
 | |
|   wxShapeEvtHandler(prev, shape)
 | |
| {
 | |
|     m_label = lab;
 | |
| }
 | |
| 
 | |
| csEvtHandler::~csEvtHandler()
 | |
| {
 | |
| }
 | |
| 
 | |
| // Copy any event handler data
 | |
| void csEvtHandler::CopyData(wxShapeEvtHandler& copy)
 | |
| {
 | |
|     wxShapeEvtHandler::CopyData(copy);
 | |
| 
 | |
|     csEvtHandler& csCopy = (csEvtHandler&) copy;
 | |
|     csCopy.m_label = m_label;
 | |
| }
 | |
|  
 | |
| void csEvtHandler::OnLeftClick(double x, double y, int keys, int attachment)
 | |
| {
 | |
|   wxClientDC dc(GetShape()->GetCanvas());
 | |
|   GetShape()->GetCanvas()->PrepareDC(dc);
 | |
| 
 | |
|   csDiagramView* view = ((csCanvas*)GetShape()->GetCanvas())->GetView();
 | |
|   view->ReflectPointSize(GetShape()->GetFont()->GetPointSize());
 | |
| 
 | |
|   if (GetShape()->IsKindOf(CLASSINFO(wxLineShape)))
 | |
|       view->ReflectArrowState((wxLineShape*) GetShape());
 | |
| 
 | |
|   csEditorToolPalette *palette = wxGetApp().GetDiagramPalette();
 | |
|   if (palette->GetSelection() == PALETTE_TEXT_TOOL)
 | |
|   {
 | |
|         view->ReflectPointSize(GetShape()->GetFont()->GetPointSize());
 | |
| 
 | |
|         EditProperties();
 | |
| #if 0
 | |
|         csLabelEditingDialog* dialog = new csLabelEditingDialog(GetShape()->GetCanvas()->GetParent());
 | |
|         dialog->SetShapeLabel(m_label);
 | |
|         if (dialog->ShowModal() == wxID_CANCEL)
 | |
|         {
 | |
|             dialog->Destroy();
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         wxString newLabel = dialog->GetShapeLabel();
 | |
|         dialog->Destroy();
 | |
| 
 | |
|         wxShape* newShape = GetShape()->CreateNewCopy();
 | |
| 
 | |
|         csEvtHandler* handler = (csEvtHandler *)newShape->GetEventHandler();
 | |
|         handler->m_label = newLabel;
 | |
| 
 | |
|         view->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Edit label", (csDiagramDocument*) view->GetDocument(),
 | |
|             new csCommandState(ID_CS_EDIT_PROPERTIES, newShape, GetShape())));
 | |
| #endif
 | |
|         return;
 | |
|   }
 | |
| 
 | |
|   if (keys == 0)
 | |
|   {
 | |
|     // If no shift key, then everything is deselected.
 | |
|     // If the shape was selected, deselect it and vice versa.
 | |
|     bool selected = GetShape()->Selected();
 | |
| 
 | |
|     view->SelectAll(FALSE);
 | |
| 
 | |
|     selected = !selected;
 | |
| 
 | |
|     GetShape()->Select(selected, &dc);
 | |
|     GetShape()->GetCanvas()->Redraw(dc); // Redraw because bits of objects will be missing
 | |
| 
 | |
|     view->SelectShape(GetShape(), selected);
 | |
|   }
 | |
|   else if (keys & KEY_SHIFT)
 | |
|   {
 | |
|     if (GetShape()->Selected())
 | |
|     {
 | |
|         GetShape()->Select(FALSE, &dc);
 | |
|         view->SelectShape(GetShape(), FALSE);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         GetShape()->Select(TRUE, &dc);
 | |
|         view->SelectShape(GetShape(), TRUE);
 | |
|     }
 | |
|     GetShape()->GetCanvas()->Redraw(dc); // Redraw because bits of objects will be missing
 | |
|   }
 | |
|   else if (keys & KEY_CTRL)
 | |
|   {
 | |
|     // Do something for CONTROL
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     ((wxFrame*)wxGetApp().GetTopWindow())->SetStatusText(m_label);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void csEvtHandler::OnRightClick(double x, double y, int keys, int attachment)
 | |
| {
 | |
|     // Have to convert back to physical coordinates from logical coordinates.
 | |
| 
 | |
|     int viewStartX, viewStartY;
 | |
|     int unitX, unitY;
 | |
|     GetShape()->GetCanvas()->ViewStart(& viewStartX, & viewStartY);
 | |
|     GetShape()->GetCanvas()->GetScrollPixelsPerUnit(& unitX, & unitY);
 | |
| 
 | |
|     int x1 = (int)(x * GetShape()->GetCanvas()->GetScaleX());
 | |
|     int y1 = (int)(y * GetShape()->GetCanvas()->GetScaleY());
 | |
| 
 | |
|     int menuX = (int) (x1 - (viewStartX * unitX)) ;
 | |
|     int menuY = (int) (y1 - (viewStartY * unitY));
 | |
| 
 | |
|     wxGetApp().GetShapeEditMenu()->SetClientData((char*) GetShape());
 | |
|     wxGetApp().GetShapeEditMenu()->Enable(ID_CS_ROTATE_CLOCKWISE, !GetShape()->IsKindOf(CLASSINFO(wxLineShape)));
 | |
|     wxGetApp().GetShapeEditMenu()->Enable(ID_CS_ROTATE_ANTICLOCKWISE, !GetShape()->IsKindOf(CLASSINFO(wxLineShape)));
 | |
| 
 | |
|     GetShape()->GetCanvas()->PopupMenu(wxGetApp().GetShapeEditMenu(), menuX, menuY);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Implement connection of two shapes by right-dragging between them.
 | |
|  */
 | |
| 
 | |
| void csEvtHandler::OnBeginDragRight(double x, double y, int keys, int attachment)
 | |
| {
 | |
|   wxClientDC dc(GetShape()->GetCanvas());
 | |
|   GetShape()->GetCanvas()->PrepareDC(dc);
 | |
| 
 | |
|   wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
 | |
|   dc.SetLogicalFunction(OGLRBLF);
 | |
|   dc.SetPen(dottedPen);
 | |
|   double xp, yp;
 | |
|   GetShape()->GetAttachmentPositionEdge(attachment, &xp, &yp);
 | |
|   dc.DrawLine(xp, yp, x, y);
 | |
|   GetShape()->GetCanvas()->CaptureMouse();
 | |
| }
 | |
| 
 | |
| void csEvtHandler::OnDragRight(bool draw, double x, double y, int keys, int attachment)
 | |
| {
 | |
|   wxClientDC dc(GetShape()->GetCanvas());
 | |
|   GetShape()->GetCanvas()->PrepareDC(dc);
 | |
| 
 | |
|   wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
 | |
|   dc.SetLogicalFunction(OGLRBLF);
 | |
|   dc.SetPen(dottedPen);
 | |
|   double xp, yp;
 | |
|   GetShape()->GetAttachmentPositionEdge(attachment, &xp, &yp);
 | |
|   dc.DrawLine(xp, yp, x, y);
 | |
| }
 | |
| 
 | |
| void csEvtHandler::OnEndDragRight(double x, double y, int keys, int attachment)
 | |
| {
 | |
|   GetShape()->GetCanvas()->ReleaseMouse();
 | |
|   csCanvas *canvas = (csCanvas *)GetShape()->GetCanvas();
 | |
| 
 | |
|   // Check if we're on an object
 | |
|   int new_attachment;
 | |
|   wxShape *otherShape = canvas->FindFirstSensitiveShape(x, y, &new_attachment, OP_DRAG_RIGHT);
 | |
|   
 | |
|   if (otherShape && !otherShape->IsKindOf(CLASSINFO(wxLineShape)))
 | |
|   {
 | |
|         wxLineShape* theShape = new csLineShape;
 | |
| 
 | |
|         theShape->AssignNewIds();
 | |
|         theShape->SetEventHandler(new csEvtHandler(theShape, theShape, wxString("")));
 | |
|         theShape->SetPen(wxBLACK_PEN);
 | |
|         theShape->SetBrush(wxRED_BRUSH);
 | |
| 
 | |
|         wxToolBar* toolbar = wxGetApp().GetDiagramToolBar();
 | |
|         bool haveArrow = toolbar->GetToolState(DIAGRAM_TOOLBAR_LINE_ARROW);
 | |
| 
 | |
|         wxLineShape *lineShape = (wxLineShape *)theShape;
 | |
| 
 | |
|         // Yes, you can have more than 2 control points, in which case
 | |
|         // it becomes a multi-segment line.
 | |
|         lineShape->MakeLineControlPoints(2);
 | |
| 
 | |
|         if (haveArrow)
 | |
|             lineShape->AddArrow(ARROW_ARROW, ARROW_POSITION_MIDDLE, 10.0, 0.0, "Normal arrowhead");
 | |
| 
 | |
|         lineShape->SetFrom(GetShape());
 | |
|         lineShape->SetTo(otherShape);
 | |
|         lineShape->SetAttachments(attachment, new_attachment);
 | |
| 
 | |
|         canvas->GetView()->GetDocument()->GetCommandProcessor()->Submit(
 | |
|             new csDiagramCommand("Line", (csDiagramDocument *)canvas->GetView()->GetDocument(),
 | |
|                     new csCommandState(ID_CS_ADD_LINE, lineShape, NULL)));
 | |
|   }
 | |
| }
 | |
| 
 | |
| static double g_DragOffsetX = 0.0;
 | |
| static double g_DragOffsetY = 0.0;
 | |
| static double g_DragStartX = 0.0;
 | |
| static double g_DragStartY = 0.0;
 | |
| 
 | |
| void csEvtHandler::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
 | |
| {
 | |
|   if ((GetShape()->GetSensitivityFilter() & OP_DRAG_LEFT) != OP_DRAG_LEFT)
 | |
|   {
 | |
|     attachment = 0;
 | |
|     double dist;
 | |
|     if (GetShape()->GetParent())
 | |
|     {
 | |
|       GetShape()->GetParent()->HitTest(x, y, &attachment, &dist);
 | |
|       GetShape()->GetParent()->GetEventHandler()->OnDragLeft(draw, x, y, keys, attachment);
 | |
|     }
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   wxClientDC dc(GetShape()->GetCanvas());
 | |
|   GetShape()->GetCanvas()->PrepareDC(dc);
 | |
| 
 | |
|   dc.SetLogicalFunction(OGLRBLF);
 | |
| 
 | |
|   wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
 | |
|   dc.SetPen(dottedPen);
 | |
|   dc.SetBrush(* wxTRANSPARENT_BRUSH);
 | |
| 
 | |
|   double xx, yy;
 | |
|   xx = x + g_DragOffsetX;
 | |
|   yy = y + g_DragOffsetY;
 | |
| 
 | |
|   GetShape()->GetCanvas()->Snap(&xx, &yy);
 | |
| 
 | |
|   double offsetX = xx - g_DragStartX;
 | |
|   double offsetY = yy - g_DragStartY;
 | |
| 
 | |
| //  m_xpos = xx; m_ypos = yy;
 | |
|   double w, h;
 | |
|   GetShape()->GetBoundingBoxMax(&w, &h);
 | |
|   GetShape()->GetEventHandler()->OnDrawOutline(dc, xx, yy, w, h);
 | |
| 
 | |
|   // Draw bounding box for other selected shapes
 | |
|   wxNode* node = GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->First();
 | |
|   while (node)
 | |
|   {
 | |
|      wxShape* shape = (wxShape*) node->Data();
 | |
|      if (shape->Selected() && !shape->IsKindOf(CLASSINFO(wxLineShape)) && (shape != GetShape()))
 | |
|      {
 | |
|         shape->GetBoundingBoxMax(&w, &h);
 | |
|         shape->OnDrawOutline(dc, shape->GetX() + offsetX, shape->GetY() + offsetY, w, h);
 | |
|      }
 | |
|      node = node->Next();
 | |
|   }
 | |
| }
 | |
| 
 | |
| void csEvtHandler::OnBeginDragLeft(double x, double y, int keys, int attachment)
 | |
| {
 | |
|   if ((GetShape()->GetSensitivityFilter() & OP_DRAG_LEFT) != OP_DRAG_LEFT)
 | |
|   {
 | |
|     attachment = 0;
 | |
|     double dist;
 | |
|     if (GetShape()->GetParent())
 | |
|     {
 | |
|       GetShape()->GetParent()->HitTest(x, y, &attachment, &dist);
 | |
|       GetShape()->GetParent()->GetEventHandler()->OnBeginDragLeft(x, y, keys, attachment);
 | |
|     }
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   wxClientDC dc(GetShape()->GetCanvas());
 | |
|   GetShape()->GetCanvas()->PrepareDC(dc);
 | |
| 
 | |
|   // New policy: don't erase shape until end of drag.
 | |
| //  Erase(dc);
 | |
| 
 | |
|   g_DragOffsetX = GetShape()->GetX() - x;
 | |
|   g_DragOffsetY = GetShape()->GetY() - y;
 | |
| 
 | |
|   double xx, yy;
 | |
|   xx = x + g_DragOffsetX;
 | |
|   yy = y + g_DragOffsetY;
 | |
| 
 | |
|   GetShape()->GetCanvas()->Snap(&xx, &yy);
 | |
| 
 | |
|   g_DragStartX = GetShape()->GetX();
 | |
|   g_DragStartY = GetShape()->GetY();
 | |
| 
 | |
|   double offsetX = xx - g_DragStartX;
 | |
|   double offsetY = yy - g_DragStartY;
 | |
| 
 | |
|   dc.SetLogicalFunction(OGLRBLF);
 | |
| 
 | |
|   wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
 | |
|   dc.SetPen(dottedPen);
 | |
|   dc.SetBrush((* wxTRANSPARENT_BRUSH));
 | |
| 
 | |
|   double w, h;
 | |
|   GetShape()->GetBoundingBoxMax(&w, &h);
 | |
|   GetShape()->GetEventHandler()->OnDrawOutline(dc, xx, yy, w, h);
 | |
| 
 | |
|   // Draw bounding box for other selected shapes
 | |
|   wxNode* node = GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->First();
 | |
|   while (node)
 | |
|   {
 | |
|      wxShape* shape = (wxShape*) node->Data();
 | |
|      if (shape->Selected() && !shape->IsKindOf(CLASSINFO(wxLineShape)) && (shape != GetShape()))
 | |
|      {
 | |
|         shape->GetBoundingBoxMax(&w, &h);
 | |
|         shape->OnDrawOutline(dc, shape->GetX() + offsetX, shape->GetY() + offsetY, w, h);
 | |
|      }
 | |
|      node = node->Next();
 | |
|   }
 | |
| 
 | |
|   GetShape()->GetCanvas()->CaptureMouse();
 | |
| }
 | |
| 
 | |
| 
 | |
| void csEvtHandler::OnEndDragLeft(double x, double y, int keys, int attachment)
 | |
| {
 | |
|   csCanvas *canvas = (csCanvas *)GetShape()->GetCanvas();
 | |
| 
 | |
|   canvas->ReleaseMouse();
 | |
|   if ((GetShape()->GetSensitivityFilter() & OP_DRAG_LEFT) != OP_DRAG_LEFT)
 | |
|   {
 | |
|     attachment = 0;
 | |
|     double dist;
 | |
|     if (GetShape()->GetParent())
 | |
|     {
 | |
|       GetShape()->GetParent()->HitTest(x, y, &attachment, &dist);
 | |
|       GetShape()->GetParent()->GetEventHandler()->OnEndDragLeft(x, y, keys, attachment);
 | |
|     }
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   wxClientDC dc(canvas);
 | |
|   canvas->PrepareDC(dc);
 | |
| 
 | |
|   dc.SetLogicalFunction(wxCOPY);
 | |
| 
 | |
|   double xx = x + g_DragOffsetX;
 | |
|   double yy = y + g_DragOffsetY;
 | |
| 
 | |
|   canvas->Snap(&xx, &yy);
 | |
| 
 | |
|   double offsetX = xx - g_DragStartX;
 | |
|   double offsetY = yy - g_DragStartY;
 | |
| 
 | |
|   wxShape* newShape = GetShape()->CreateNewCopy();
 | |
| 
 | |
|   newShape->SetX(xx);
 | |
|   newShape->SetY(yy);
 | |
| 
 | |
|   csDiagramCommand* cmd = new csDiagramCommand("Move", (csDiagramDocument*)canvas->GetView()->GetDocument(),
 | |
|                 new csCommandState(ID_CS_MOVE, newShape, GetShape()));
 | |
| 
 | |
|   // Move line points
 | |
|   wxNode* node = GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->First();
 | |
|   while (node)
 | |
|   {
 | |
|      wxShape* shape = (wxShape*) node->Data();
 | |
|      // Only move the line point(s) if both ends move too
 | |
|      if (shape->IsKindOf(CLASSINFO(wxLineShape)) &&
 | |
|            ((wxLineShape*)shape)->GetTo()->Selected() && ((wxLineShape*)shape)->GetFrom()->Selected())
 | |
|      {
 | |
|         wxLineShape* lineShape = (wxLineShape*) shape;
 | |
| 
 | |
|         if (lineShape->GetLineControlPoints()->Number() > 2)
 | |
|         {
 | |
|             wxLineShape* newLineShape = (wxLineShape*) lineShape->CreateNewCopy();
 | |
| 
 | |
|             wxNode *node1 = newLineShape->GetLineControlPoints()->First();
 | |
|             while (node1)
 | |
|             {
 | |
|                 wxRealPoint *point = (wxRealPoint *)node1->Data();
 | |
|                 point->x += offsetX;
 | |
|                 point->y += offsetY;
 | |
|                 node1 = node1->Next();
 | |
|             }
 | |
|             cmd->AddState(new csCommandState(ID_CS_MOVE_LINE_POINT, newLineShape, lineShape));
 | |
|             lineShape->Erase(dc);
 | |
|         }
 | |
|      }
 | |
|      node = node->Next();
 | |
|   }
 | |
| 
 | |
|   // Add other selected node shapes, if any
 | |
|   node = GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->First();
 | |
|   while (node)
 | |
|   {
 | |
|      wxShape* shape = (wxShape*) node->Data();
 | |
|      if (shape->Selected() && !shape->IsKindOf(CLASSINFO(wxLineShape)) && (shape != GetShape()))
 | |
|      {
 | |
|         wxShape* newShape2 = shape->CreateNewCopy();
 | |
|         newShape2->SetX(shape->GetX() + offsetX);
 | |
|         newShape2->SetY(shape->GetY() + offsetY);
 | |
|         cmd->AddState(new csCommandState(ID_CS_MOVE, newShape2, shape));
 | |
|      }
 | |
|      node = node->Next();
 | |
|   }
 | |
| 
 | |
|   canvas->GetView()->GetDocument()->GetCommandProcessor()->Submit(cmd);
 | |
| }
 | |
| 
 | |
| void csEvtHandler::OnSizingEndDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment)
 | |
| {
 | |
|   wxShape* shape = GetShape();
 | |
|   csCanvas *canvas = (csCanvas *)GetShape()->GetCanvas();
 | |
| 
 | |
|   if (shape->IsKindOf(CLASSINFO(wxLineShape)))
 | |
|   {
 | |
|     // TODO: Do/Undo support for line operations
 | |
|     ((wxLineShape*)shape)->wxLineShape::OnSizingEndDragLeft(pt, x, y, keys, attachment);
 | |
| #if 0
 | |
|         wxLineShape* lineShape = (wxLineShape*) shape;
 | |
| 
 | |
|         wxLineControlPoint* lpt = (wxLineControlPoint*) pt;
 | |
| 
 | |
|         wxClientDC dc(canvas);
 | |
|         canvas->PrepareDC(dc);
 | |
| 
 | |
|         shape->SetDisableLabel(FALSE);
 | |
| 
 | |
|         if (lpt->m_type == CONTROL_POINT_LINE)
 | |
|         {
 | |
|             canvas->Snap(&x, &y);
 | |
| 
 | |
|             dc.SetLogicalFunction(wxCOPY);
 | |
|             lpt->SetX(x); lpt->SetY(y);
 | |
|             lpt->m_point->x = x; lpt->m_point->y = y;
 | |
| 
 | |
|             this->OnMoveLink(dc);
 | |
|         }
 | |
|         if (lpt->m_type == CONTROL_POINT_ENDPOINT_FROM)
 | |
|         {
 | |
|             if (lpt->m_oldCursor)
 | |
|                 canvas->SetCursor(lpt->m_oldCursor);
 | |
|             lineShape->Erase(dc);
 | |
| 
 | |
|             lpt->SetX(x); lpt->SetY(y);
 | |
| 
 | |
|             if (lineShape->GetFrom())
 | |
|             {
 | |
|                 lineShape->GetFrom()->MoveLineToNewAttachment(dc, lineShape, x, y);
 | |
|             }
 | |
|         }
 | |
|         if (lpt->m_type == CONTROL_POINT_ENDPOINT_TO)
 | |
|         {
 | |
|             if (lpt->m_oldCursor)
 | |
|                 canvas->SetCursor(lpt->m_oldCursor);
 | |
| 
 | |
|             lpt->SetX(x); lpt->SetY(y);
 | |
| 
 | |
|             if (lineShape->GetTo())
 | |
|             {
 | |
|                 lineShape->GetTo()->MoveLineToNewAttachment(dc, lineShape, x, y);
 | |
|             }
 | |
|         }
 | |
| #endif
 | |
|         return;
 | |
|   }
 | |
| 
 | |
|   wxClientDC dc(canvas);
 | |
|   canvas->PrepareDC(dc);
 | |
| 
 | |
|   canvas->ReleaseMouse();
 | |
|   dc.SetLogicalFunction(wxCOPY);
 | |
| 
 | |
| //  shape->Erase(dc);
 | |
| /*
 | |
|   shape->Recompute();
 | |
|   shape->ResetControlPoints();
 | |
|   if (!pt->m_eraseObject)
 | |
|     shape->Show(FALSE);
 | |
| */
 | |
| 
 | |
|   wxShape* newShape = shape->CreateNewCopy();
 | |
| 
 | |
|   if (newShape->IsKindOf(CLASSINFO(wxPolygonShape)))
 | |
|   {
 | |
|     wxPolygonControlPoint* ppt = (wxPolygonControlPoint*) pt;
 | |
|     newShape->SetSize(ppt->GetNewSize().x, ppt->GetNewSize().y);
 | |
| 
 | |
|     ((wxPolygonShape *)newShape)->CalculateBoundingBox();
 | |
|     ((wxPolygonShape *)newShape)->CalculatePolygonCentre();
 | |
|     newShape->ResetControlPoints();
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     newShape->SetSize(pt->sm_controlPointDragEndWidth, pt->sm_controlPointDragEndHeight);
 | |
|     if (shape->GetCentreResize())
 | |
|     {
 | |
|       // Old position is fine
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       newShape->SetX(pt->sm_controlPointDragPosX);
 | |
|       newShape->SetY(pt->sm_controlPointDragPosY);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   csDiagramCommand* cmd = new csDiagramCommand("Size", (csDiagramDocument*)canvas->GetView()->GetDocument(),
 | |
|                 new csCommandState(ID_CS_SIZE, newShape, shape));
 | |
| 
 | |
|   canvas->GetView()->GetDocument()->GetCommandProcessor()->Submit(cmd);
 | |
| 
 | |
| }
 | |
| 
 | |
| void csEvtHandler::OnEndSize(double x, double y)
 | |
| {
 | |
|   wxClientDC dc(GetShape()->GetCanvas());
 | |
|   GetShape()->GetCanvas()->PrepareDC(dc);
 | |
| 
 | |
|   GetShape()->FormatText(dc, m_label);
 | |
| }
 | |
| 
 | |
| void csEvtHandler::OnChangeAttachment(int attachment, wxLineShape* line, wxList& ordering)
 | |
| {
 | |
|     csCanvas *canvas = (csCanvas *)GetShape()->GetCanvas();
 | |
| 
 | |
|     // We actually submit two different states: one to change the ordering, and another
 | |
|     // to change the attachment for the line.
 | |
|     // Problem. If we refresh after the attachment change, we'll get a flicker.
 | |
|     // We really want to do both in a oner.
 | |
| 
 | |
|     csDiagramCommand* cmd = new csDiagramCommand("Change attachment", (csDiagramDocument*)canvas->GetView()->GetDocument());
 | |
| 
 | |
|     wxLineShape* newLine = (wxLineShape*) line->CreateNewCopy();
 | |
|     if (line->GetTo() == GetShape())
 | |
|         newLine->SetAttachmentTo(attachment);
 | |
|     else
 | |
|         newLine->SetAttachmentFrom(attachment);
 | |
| 
 | |
|     cmd->AddState(new csCommandState(ID_CS_CHANGE_LINE_ATTACHMENT, newLine, line));
 | |
| 
 | |
|     // Change ordering
 | |
|     wxShape* newShape = GetShape()->CreateNewCopy();
 | |
|     newShape->ApplyAttachmentOrdering(ordering);
 | |
| 
 | |
|     cmd->AddState(new csCommandState(ID_CS_CHANGE_LINE_ORDERING, newShape, GetShape()));
 | |
| 
 | |
|     canvas->GetView()->GetDocument()->GetCommandProcessor()->Submit(cmd);
 | |
| }
 | |
| 
 | |
| void csEvtHandler::OnLeftDoubleClick(double x, double y, int keys, int attachment)
 | |
| {
 | |
|     EditProperties();
 | |
| }
 | |
| 
 | |
| // Popup up a property dialog
 | |
| bool csEvtHandler::EditProperties()
 | |
| {
 | |
|     wxShape* shape = GetShape();
 | |
| 
 | |
|     // For now, no line property editing
 | |
|     if (shape->IsKindOf(CLASSINFO(wxLineShape)))
 | |
|         return FALSE;
 | |
| 
 | |
|     csDiagramView* view = ((csCanvas*)shape->GetCanvas())->GetView();
 | |
| 
 | |
|     wxPanel* attributeDialog;
 | |
|     wxString attributeDialogName;
 | |
|     wxString title;
 | |
| 
 | |
|     if (shape->IsKindOf(CLASSINFO(csThinRectangleShape)))
 | |
|     {
 | |
|         attributeDialog = new csThinRectangleDialog;
 | |
|         attributeDialogName = "thin_rectangle";
 | |
|         title = "Thin Rectangle Properties";
 | |
|     }
 | |
|     else if (shape->IsKindOf(CLASSINFO(csWideRectangleShape)))
 | |
|     {
 | |
|         attributeDialog = new csWideRectangleDialog;
 | |
|         attributeDialogName = "wide_rectangle";
 | |
|         title = "Wide Rectangle Properties";
 | |
|     }
 | |
|     else if (shape->IsKindOf(CLASSINFO(csTriangleShape)))
 | |
|     {
 | |
|         attributeDialog = new csTriangleDialog;
 | |
|         attributeDialogName = "triangle";
 | |
|         title = "Triangle Properties";
 | |
|     }
 | |
|     else if (shape->IsKindOf(CLASSINFO(csSemiCircleShape)))
 | |
|     {
 | |
|         attributeDialog = new csSemiCircleDialog;
 | |
|         attributeDialogName = "semi_circle";
 | |
|         title = "Semicircle Properties";
 | |
|     }
 | |
|     else if (shape->IsKindOf(CLASSINFO(csCircleShape)))
 | |
|     {
 | |
|         attributeDialog = new csCircleDialog;
 | |
|         attributeDialogName = "circle";
 | |
|         title = "Circle Properties";
 | |
|     }
 | |
|     else if (shape->IsKindOf(CLASSINFO(csCircleShadowShape)))
 | |
|     {
 | |
|         attributeDialog = new csCircleShadowDialog;
 | |
|         attributeDialogName = "circle_shadow";
 | |
|         title = "Circle Shadow Properties";
 | |
|     }
 | |
|     else if (shape->IsKindOf(CLASSINFO(csTextBoxShape)))
 | |
|     {
 | |
|         attributeDialog = new csTextBoxDialog;
 | |
|         attributeDialogName = "text_box";
 | |
|         title = "Text Box Properties";
 | |
|     }
 | |
|     else if (shape->IsKindOf(CLASSINFO(csGroupShape)))
 | |
|     {
 | |
|         attributeDialog = new csGroupDialog;
 | |
|         attributeDialogName = "group";
 | |
|         title = "Group Properties";
 | |
|     }
 | |
|     else if (shape->IsKindOf(CLASSINFO(csOctagonShape)))
 | |
|     {
 | |
|         attributeDialog = new csOctagonDialog;
 | |
|         attributeDialogName = "octagon";
 | |
|         title = "Octagon Properties";
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         wxMessageBox("Unrecognised shape.", "Studio", wxICON_EXCLAMATION);
 | |
|         return FALSE;
 | |
|     }
 | |
| 
 | |
|     csShapePropertiesDialog* dialog = new csShapePropertiesDialog(shape->GetCanvas()->GetParent(), title, attributeDialog, attributeDialogName);
 | |
|     dialog->GetGeneralPropertiesDialog()->SetShapeLabel(m_label);
 | |
|     if (dialog->ShowModal() == wxID_CANCEL)
 | |
|     {
 | |
|         dialog->Destroy();
 | |
|         return FALSE;
 | |
|     }
 | |
| 
 | |
|     wxString newLabel = dialog->GetGeneralPropertiesDialog()->GetShapeLabel();
 | |
|     dialog->Destroy();
 | |
| 
 | |
|     wxShape* newShape = shape->CreateNewCopy();
 | |
| 
 | |
|     csEvtHandler* handler2 = (csEvtHandler *)newShape->GetEventHandler();
 | |
|     handler2->m_label = newLabel;
 | |
| 
 | |
|     view->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Edit properties", (csDiagramDocument*) view->GetDocument(),
 | |
|                 new csCommandState(ID_CS_EDIT_PROPERTIES, newShape, shape)));
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Diagram
 | |
|  */
 | |
|  
 | |
| bool csDiagram::OnShapeSave(wxExprDatabase& db, wxShape& shape, wxExpr& expr)
 | |
| {
 | |
|   wxDiagram::OnShapeSave(db, shape, expr);
 | |
|   csEvtHandler *handler = (csEvtHandler *)shape.GetEventHandler();
 | |
|   expr.AddAttributeValueString("label", handler->m_label);
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| bool csDiagram::OnShapeLoad(wxExprDatabase& db, wxShape& shape, wxExpr& expr)
 | |
| {
 | |
|   wxDiagram::OnShapeLoad(db, shape, expr);
 | |
|   wxString label("");
 | |
|   expr.GetAttributeValue("label", label);
 | |
|   csEvtHandler *handler = new csEvtHandler(&shape, &shape, label);
 | |
|   shape.SetEventHandler(handler);
 | |
|   
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| IMPLEMENT_DYNAMIC_CLASS(csThinRectangleShape, wxDrawnShape)
 | |
| 
 | |
| csThinRectangleShape::csThinRectangleShape()
 | |
| {
 | |
|     SetDrawnPen(wxBLACK_PEN);
 | |
|     wxBrush* brush = wxTheBrushList->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID);
 | |
|     SetDrawnBrush(brush);
 | |
| 
 | |
|     double w = csSTANDARD_SHAPE_WIDTH/2;
 | |
|     double h = csSTANDARD_SHAPE_WIDTH;
 | |
| 
 | |
|     DrawRectangle(wxRect(- w/2, - h/2, w, h));
 | |
|     CalculateSize();
 | |
| 
 | |
|     SetAttachmentMode(ATTACHMENT_MODE_BRANCHING);
 | |
|     SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
 | |
|     SetCentreResize(FALSE);
 | |
| }
 | |
| 
 | |
| IMPLEMENT_DYNAMIC_CLASS(csWideRectangleShape, wxDrawnShape)
 | |
| 
 | |
| csWideRectangleShape::csWideRectangleShape()
 | |
| {
 | |
|     SetDrawnPen(wxBLACK_PEN);
 | |
|     wxBrush* brush = wxTheBrushList->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID);
 | |
|     SetDrawnBrush(brush);
 | |
| 
 | |
|     double w = csSTANDARD_SHAPE_WIDTH;
 | |
|     double h = w/2.0;
 | |
| 
 | |
|     DrawRoundedRectangle(wxRect(- w/2, - h/2, w, h), -0.3);
 | |
|     CalculateSize();
 | |
| 
 | |
|     SetAttachmentMode(ATTACHMENT_MODE_BRANCHING);
 | |
|     SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
 | |
|     SetCentreResize(FALSE);
 | |
| }
 | |
| 
 | |
| IMPLEMENT_DYNAMIC_CLASS(csTriangleShape, wxDrawnShape)
 | |
| 
 | |
| csTriangleShape::csTriangleShape()
 | |
| {
 | |
|     SetDrawnPen(wxBLACK_PEN);
 | |
|     wxBrush* brush = wxTheBrushList->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID);
 | |
|     SetDrawnBrush(brush);
 | |
| 
 | |
|     double w = csSTANDARD_SHAPE_WIDTH;
 | |
|     double h = (csSTANDARD_SHAPE_WIDTH*2.0)/3.0;
 | |
| 
 | |
|     // Triangle, from top vertex
 | |
|     wxPoint* points = new wxPoint[3];
 | |
| 
 | |
| 
 | |
|     points[0] = wxPoint( 0 ,  - h / 2 );
 | |
|     points[1] = wxPoint( w / 2 ,  h / 2 );
 | |
|     points[2] = wxPoint( -w / 2,  h / 2 );
 | |
| 
 | |
|     DrawPolygon(3, points, oglMETAFLAGS_OUTLINE);
 | |
| 
 | |
|     delete[] points;
 | |
| 
 | |
|     // Add another triangle at the top for the black bit
 | |
|     SetDrawnBrush(wxBLACK_BRUSH);
 | |
| 
 | |
|     points = new wxPoint[3];
 | |
| 
 | |
|     // Calculate where the new points will be, using the proportions
 | |
|     // of the triangle.
 | |
|     double h1 = 8; // Height of little triangle.
 | |
| 
 | |
|     /*
 | |
|         Formula: ((w/2) / h) = w1 / h1
 | |
|         w1 = ((w/2) / h) * h1;
 | |
|     */
 | |
|     double ratio = ((w/2.0) / h) ;
 | |
|     double w1 = ratio * h1;
 | |
| 
 | |
|     points[0] = wxPoint(0  ,  (int) (- h / 2 ));
 | |
|     points[1] = wxPoint( (int) w1,  (int) (- h / 2 + h1));
 | |
|     points[2] = wxPoint( (int) -w1, (int) (- h / 2 + h1));
 | |
| 
 | |
|     DrawPolygon(3, points);
 | |
| 
 | |
|     delete[] points;
 | |
| 
 | |
|     CalculateSize();
 | |
| 
 | |
|     SetAttachmentMode(ATTACHMENT_MODE_BRANCHING);
 | |
|     SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
 | |
|     SetCentreResize(FALSE);
 | |
| }
 | |
| 
 | |
| IMPLEMENT_DYNAMIC_CLASS(csSemiCircleShape, wxDrawnShape)
 | |
| 
 | |
| csSemiCircleShape::csSemiCircleShape()
 | |
| {
 | |
|     // Zero degrees
 | |
|     DrawAtAngle(oglDRAWN_ANGLE_0);
 | |
| 
 | |
|     double w = csSTANDARD_SHAPE_WIDTH;
 | |
|     double h = w/2.0;
 | |
| 
 | |
|     SetDrawnPen(wxTRANSPARENT_PEN);
 | |
|     SetDrawnBrush(wxTRANSPARENT_BRUSH);
 | |
| 
 | |
|     // Draw a dummy rectangle that will be used for calculating the
 | |
|     // bounding box, since we can't calculate the bounding box for
 | |
|     // an arbitrary arc (not implemented)
 | |
| 
 | |
|     DrawRectangle(wxRect(-w/2.0, -h/2.0, w, h));
 | |
| 
 | |
|     SetDrawnPen(wxBLACK_PEN);
 | |
|     wxBrush* brush = wxTheBrushList->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID);
 | |
|     SetDrawnBrush(brush);
 | |
| 
 | |
|     DrawEllipticArc(wxRect(-w/2, -h/2, w, 2*h), 0.0, 180.0);
 | |
|     DrawLine(wxPoint(-w/2, h/2), wxPoint(w/2, h/2));
 | |
| 
 | |
|     CalculateSize();
 | |
| 
 | |
|     /// 90 degrees
 | |
| 
 | |
|     w = csSTANDARD_SHAPE_WIDTH/2;
 | |
|     h = csSTANDARD_SHAPE_WIDTH;
 | |
| 
 | |
|     DrawAtAngle(oglDRAWN_ANGLE_90);
 | |
| 
 | |
|     SetDrawnPen(wxTRANSPARENT_PEN);
 | |
|     SetDrawnBrush(wxTRANSPARENT_BRUSH);
 | |
| 
 | |
|     DrawRectangle(wxRect(-w/2, -h/2, w, h));
 | |
| 
 | |
|     SetDrawnPen(wxBLACK_PEN);
 | |
|     SetDrawnBrush(brush);
 | |
| 
 | |
|     DrawEllipticArc(wxRect(-w/2 - w, -h/2, 2*w, h), 270.0, 90.0);
 | |
|     DrawLine(wxPoint(-w/2, -h/2), wxPoint(-w/2, h/2));
 | |
| 
 | |
|     CalculateSize();
 | |
| 
 | |
|     /// 180 degrees
 | |
| 
 | |
|     DrawAtAngle(oglDRAWN_ANGLE_180);
 | |
| 
 | |
|     w = csSTANDARD_SHAPE_WIDTH;
 | |
|     h = csSTANDARD_SHAPE_WIDTH/2;
 | |
| 
 | |
|     SetDrawnPen(wxTRANSPARENT_PEN);
 | |
|     SetDrawnBrush(wxTRANSPARENT_BRUSH);
 | |
| 
 | |
|     DrawRectangle(wxRect(-w/2, -h/2, w, h));
 | |
| 
 | |
|     SetDrawnPen(wxBLACK_PEN);
 | |
|     SetDrawnBrush(brush);
 | |
| 
 | |
|     DrawEllipticArc(wxRect(-w/2, -h/2 - h, w, 2*h), 180.0, 0.0);
 | |
|     DrawLine(wxPoint(-w/2, -h/2), wxPoint(w/2, -h/2));
 | |
| 
 | |
|     CalculateSize();
 | |
| 
 | |
|     /// 270 degrees
 | |
| 
 | |
|     DrawAtAngle(oglDRAWN_ANGLE_270);
 | |
| 
 | |
|     w = csSTANDARD_SHAPE_WIDTH/2;
 | |
|     h = csSTANDARD_SHAPE_WIDTH;
 | |
| 
 | |
|     SetDrawnPen(wxTRANSPARENT_PEN);
 | |
|     SetDrawnBrush(wxTRANSPARENT_BRUSH);
 | |
| 
 | |
|     DrawRectangle(wxRect(-w/2, -h/2, w, h));
 | |
| 
 | |
|     SetDrawnPen(wxBLACK_PEN);
 | |
|     SetDrawnBrush(brush);
 | |
| 
 | |
|     DrawEllipticArc(wxRect(-w/2, -h/2, 2*w, h), 90.0, 270.0);
 | |
|     DrawLine(wxPoint(w/2, -h/2), wxPoint(w/2, h/2));
 | |
| 
 | |
|     CalculateSize();
 | |
| 
 | |
|     // Reset to zero
 | |
|     DrawAtAngle(oglDRAWN_ANGLE_0);
 | |
|     CalculateSize();
 | |
| 
 | |
|     SetAttachmentMode(ATTACHMENT_MODE_BRANCHING);
 | |
|     SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
 | |
|     SetCentreResize(FALSE);
 | |
| }
 | |
| 
 | |
| IMPLEMENT_DYNAMIC_CLASS(csCircleShape, wxCircleShape)
 | |
| 
 | |
| csCircleShape::csCircleShape()
 | |
| {
 | |
|     SetPen(wxBLACK_PEN);
 | |
|     wxBrush* brush = wxTheBrushList->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID);
 | |
|     SetBrush(brush);
 | |
| 
 | |
|     SetSize(csSTANDARD_SHAPE_WIDTH*0.6, csSTANDARD_SHAPE_WIDTH*0.6);
 | |
| 
 | |
|     SetAttachmentMode(ATTACHMENT_MODE_BRANCHING);
 | |
|     SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
 | |
|     SetCentreResize(FALSE);
 | |
| }
 | |
| 
 | |
| IMPLEMENT_DYNAMIC_CLASS(csCircleShadowShape, wxCircleShape)
 | |
| 
 | |
| csCircleShadowShape::csCircleShadowShape()
 | |
| {
 | |
|     SetPen(wxBLACK_PEN);
 | |
|     wxBrush* brush = wxTheBrushList->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID);
 | |
|     SetBrush(brush);
 | |
| 
 | |
|     SetSize(csSTANDARD_SHAPE_WIDTH*0.6, csSTANDARD_SHAPE_WIDTH*0.6);
 | |
| 
 | |
|     SetAttachmentMode(ATTACHMENT_MODE_BRANCHING);
 | |
|     SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
 | |
|     SetCentreResize(FALSE);
 | |
|     SetShadowMode(SHADOW_RIGHT);
 | |
| }
 | |
| 
 | |
| IMPLEMENT_DYNAMIC_CLASS(csOctagonShape, wxPolygonShape)
 | |
| 
 | |
| csOctagonShape::csOctagonShape()
 | |
| {
 | |
|     SetPen(wxBLACK_PEN);
 | |
|     SetBrush(wxTheBrushList->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID));
 | |
| 
 | |
|     double w = csSTANDARD_SHAPE_WIDTH*0.5;
 | |
|     double h = csSTANDARD_SHAPE_WIDTH*0.5;
 | |
| 
 | |
|     double prop = h/3.0;
 | |
| 
 | |
|     wxList* points = new wxList;
 | |
|     points->Append((wxObject*) new wxRealPoint(-w/2.0 + prop, -h/2.0));
 | |
|     points->Append((wxObject*) new wxRealPoint(w/2.0 - prop, -h/2.0));
 | |
|     points->Append((wxObject*) new wxRealPoint(w/2.0, -h/2.0 + prop));
 | |
|     points->Append((wxObject*) new wxRealPoint(w/2.0, h/2.0 - prop));
 | |
|     points->Append((wxObject*) new wxRealPoint(w/2.0 - prop, h/2.0));
 | |
|     points->Append((wxObject*) new wxRealPoint(-w/2.0 + prop, h/2.0));
 | |
|     points->Append((wxObject*) new wxRealPoint(-w/2.0, h/2.0 - prop));
 | |
|     points->Append((wxObject*) new wxRealPoint(-w/2.0, -h/2.0 + prop));
 | |
| 
 | |
|     Create(points);
 | |
| 
 | |
|     SetAttachmentMode(ATTACHMENT_MODE_BRANCHING);
 | |
|     SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
 | |
|     SetCentreResize(FALSE);
 | |
| }
 | |
| 
 | |
| // This is a transparent shape for drawing around other shapes.
 | |
| IMPLEMENT_DYNAMIC_CLASS(csGroupShape, wxRectangleShape)
 | |
| 
 | |
| csGroupShape::csGroupShape()
 | |
| {
 | |
|     SetPen(wxThePenList->FindOrCreatePen("BLACK", 1, wxDOT));
 | |
|     SetBrush(wxTRANSPARENT_BRUSH);
 | |
| 
 | |
|     SetSize(csSTANDARD_SHAPE_WIDTH, csSTANDARD_SHAPE_WIDTH);
 | |
|     SetCentreResize(FALSE);
 | |
| }
 | |
| 
 | |
| void csGroupShape::OnDraw(wxDC& dc)
 | |
| {
 | |
|     wxRectangleShape::OnDraw(dc);
 | |
| }
 | |
| 
 | |
| // Must modify the hit-test so it doesn't obscure shapes that are inside.
 | |
| bool csGroupShape::HitTest(double x, double y, int* attachment, double* distance)
 | |
| {
 | |
|     *attachment = 0;
 | |
|     *distance = 0.0;
 | |
| 
 | |
|     double width = 0.0, height = 0.0;
 | |
|     GetBoundingBoxMin(&width, &height);
 | |
| 
 | |
|     double x1 = GetX() - (width/2.0);
 | |
|     double y1 = GetY() - (height/2.0);
 | |
|     double x2 = GetX() + (width/2.0);
 | |
|     double y2 = GetY() + (height/2.0);
 | |
| 
 | |
|     double edgeTolerance = 4.0;
 | |
| 
 | |
|     // Test each edge in turn
 | |
| 
 | |
|     // Top/bottom edges
 | |
|     if (x >= x1 && x <= x2)
 | |
|     {
 | |
|         if ((y >= y1 - edgeTolerance) && (y <= y1 + edgeTolerance))
 | |
|             return TRUE;
 | |
|         if ((y <= y2 + edgeTolerance) && (y >= y2 - edgeTolerance))
 | |
|             return TRUE;
 | |
|     }
 | |
|     // Left/right edges
 | |
|     if (y >= y1 && y <= y2)
 | |
|     {
 | |
|         if ((x >= x1 - edgeTolerance) && (x <= x1 + edgeTolerance))
 | |
|             return TRUE;
 | |
|         if ((x <= x2 + edgeTolerance) && (x >= x2 - edgeTolerance))
 | |
|             return TRUE;
 | |
|     }
 | |
| 
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| IMPLEMENT_DYNAMIC_CLASS(csTextBoxShape, wxRectangleShape)
 | |
| 
 | |
| csTextBoxShape::csTextBoxShape()
 | |
| {
 | |
|     SetPen(wxTRANSPARENT_PEN);
 | |
|     SetBrush(wxTRANSPARENT_BRUSH);
 | |
| 
 | |
|     SetSize(csSTANDARD_SHAPE_WIDTH, csSTANDARD_SHAPE_WIDTH/2.0);
 | |
| 
 | |
|     SetAttachmentMode(ATTACHMENT_MODE_NONE);
 | |
|     SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
 | |
|     SetCentreResize(FALSE);
 | |
| }
 | |
| 
 | |
| IMPLEMENT_DYNAMIC_CLASS(csLineShape, wxLineShape)
 | |
| 
 | |
| csLineShape::csLineShape()
 | |
| {
 | |
| }
 | |
| 
 | |
| bool csLineShape::OnMoveMiddleControlPoint(wxDC& dc, wxLineControlPoint* lpt, const wxRealPoint& pt)
 | |
| {
 | |
|     csDiagramView* view = ((csCanvas*)GetCanvas())->GetView();
 | |
| 
 | |
|     // Temporarily set the new shape properties so we can copy it
 | |
|     lpt->SetX(pt.x); lpt->SetY(pt.y);
 | |
|     lpt->m_point->x = pt.x; lpt->m_point->y = pt.y;
 | |
| 
 | |
|     wxLineShape* newShape = (wxLineShape*) this->CreateNewCopy();
 | |
| 
 | |
|     // Now set them back again
 | |
|     lpt->SetX(lpt->m_originalPos.x); lpt->SetY(lpt->m_originalPos.y);
 | |
|     lpt->m_point->x = lpt->m_originalPos.x; lpt->m_point->y = lpt->m_originalPos.y;
 | |
| 
 | |
|     view->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Move line point", (csDiagramDocument*) view->GetDocument(),
 | |
|                 new csCommandState(ID_CS_MOVE_LINE_POINT, newShape, this)));
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| wxLabelShape* csLineShape::OnCreateLabelShape(wxLineShape *parent, wxShapeRegion *region, double w, double h)
 | |
| {
 | |
|     return new csLabelShape(parent, region, w, h);
 | |
| }
 | |
| 
 | |
| #if 0
 | |
| bool csLineShape::OnLabelMovePre(wxDC& dc, wxLabelShape* labelShape, double x, double y, double old_x, double old_y, bool display)
 | |
| {
 | |
|     csDiagramView* view = ((csCanvas*)GetCanvas())->GetView();
 | |
| 
 | |
|     wxLineShape* newShape = (wxLineShape*) this->CreateNewCopy();
 | |
| 
 | |
|     wxLineShape::OnLabelMovePre(dc, labelShape, x, y, old_x, old_y, display);
 | |
| 
 | |
|     view->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Move label", (csDiagramDocument*) view->GetDocument(),
 | |
|                 new csCommandState(ID_CS_MOVE_LABEL, newShape, this)));
 | |
|   return TRUE;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| IMPLEMENT_DYNAMIC_CLASS(csLabelShape, wxLabelShape)
 | |
| 
 | |
| csLabelShape::csLabelShape(wxLineShape *parent, wxShapeRegion *region, double w, double h):
 | |
|   wxLabelShape(parent, region, w, h)
 | |
| {
 | |
| }
 | |
| 
 | |
| // TODO: not sure how intercept normal behaviour (OnMovePre) to make
 | |
| // label movement undo-able.
 | |
| void csLabelShape::OnEndDragLeft(double x, double y, int keys, int attachment)
 | |
| {
 | |
|     wxLabelShape::OnEndDragLeft(x, y, keys, attachment);
 | |
| }
 | |
| 
 | |
| 
 | |
| // Menu for editing shapes
 | |
| void studioShapeEditProc(wxMenu& menu, wxCommandEvent& event)
 | |
| {
 | |
|     wxShape* shape = (wxShape*) menu.GetClientData();
 | |
|     csDiagramView* view = ((csCanvas*)shape->GetCanvas())->GetView();
 | |
| 
 | |
|     switch (event.GetId())
 | |
|     {
 | |
|         case ID_CS_EDIT_PROPERTIES:
 | |
|         {
 | |
|             csEvtHandler* handler1 = (csEvtHandler *)shape->GetEventHandler();
 | |
|             handler1->EditProperties();
 | |
| #if 0
 | |
|             csEvtHandler* handler1 = (csEvtHandler *)shape->GetEventHandler();
 | |
|             csLabelEditingDialog* dialog = new csLabelEditingDialog(shape->GetCanvas()->GetParent());
 | |
|             dialog->SetShapeLabel(handler1->m_label);
 | |
|             if (dialog->ShowModal() == wxID_CANCEL)
 | |
|             {
 | |
|                 dialog->Destroy();
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             wxString newLabel = dialog->GetShapeLabel();
 | |
|             dialog->Destroy();
 | |
| 
 | |
|             wxShape* newShape = shape->CreateNewCopy();
 | |
| 
 | |
|             csEvtHandler* handler2 = (csEvtHandler *)newShape->GetEventHandler();
 | |
|             handler2->m_label = newLabel;
 | |
| 
 | |
|             view->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Edit label", (csDiagramDocument*) view->GetDocument(),
 | |
|                 new csCommandState(ID_CS_EDIT_LABEL, newShape, shape)));
 | |
| #endif
 | |
|             break;
 | |
|         }
 | |
|         case wxID_CUT:
 | |
|         {
 | |
|             wxList list;
 | |
|             list.Append(shape);
 | |
|             view->DoCut(list);
 | |
|             break;
 | |
|         }
 | |
|         case ID_CS_ROTATE_CLOCKWISE:
 | |
|         case ID_CS_ROTATE_ANTICLOCKWISE:
 | |
|         {
 | |
|             if (shape->IsKindOf(CLASSINFO(wxLineShape)))
 | |
|                 break;
 | |
| 
 | |
|             double theta = shape->GetRotation();
 | |
|             const double myPi = 3.1415926535897932384626433832795 ;
 | |
|             double ninetyDegrees = myPi/2.0;
 | |
| 
 | |
|             wxString opStr;
 | |
|             if (event.GetId() == ID_CS_ROTATE_CLOCKWISE)
 | |
|             {
 | |
|                 theta += ninetyDegrees;
 | |
|                 opStr = "Rotate clockwise";
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 theta -= ninetyDegrees;
 | |
|                 opStr = "Rotate anticlockwise";
 | |
|             }
 | |
| 
 | |
|             if (theta >= 2.0*myPi || theta < 0.0)
 | |
|                 theta = 0.0;
 | |
|             wxShape* newShape = shape->CreateNewCopy();
 | |
|             newShape->Rotate(0.0, 0.0, theta);
 | |
|             wxList newShapes;
 | |
|             wxList oldShapes;
 | |
|             newShapes.Append(newShape);
 | |
|             oldShapes.Append(shape);
 | |
|             view->DoCmd(newShapes, oldShapes, event.GetId(), opStr);
 | |
|             break;
 | |
|         }
 | |
|         default:
 | |
|             break;
 | |
|     }
 | |
| }
 | |
| 
 | |
| BEGIN_EVENT_TABLE(ShapeEditMenu, wxMenu)
 | |
|     EVT_COMMAND_RANGE(1, 65000, wxEVT_COMMAND_MENU_SELECTED, ShapeEditMenu::OnCommand)
 | |
| END_EVENT_TABLE()
 | |
| 
 | |
| void ShapeEditMenu::OnCommand(wxCommandEvent& event)
 | |
| {
 | |
|     studioShapeEditProc(*this, event);
 | |
| }
 | |
| 
 |