2000-03-03 06:25:10 -05:00
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// 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".
|
2001-10-30 08:33:34 -05:00
|
|
|
#include "wx/wxprec.h"
|
2000-03-03 06:25:10 -05:00
|
|
|
|
|
|
|
#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);
|
|
|
|
}
|
|
|
|
|