1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Implements Studio shapes
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 // #pragma implementation
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
27 #if !wxUSE_DOC_VIEW_ARCHITECTURE
28 #error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in wx_setup.h!
31 #include <wx/wxexpr.h>
37 #include <wx/ogl/basicp.h>
38 #include <wx/ogl/linesp.h>
39 #include "cspalette.h"
42 #define csSTANDARD_SHAPE_WIDTH 100
44 IMPLEMENT_CLASS(csDiagram
, wxDiagram
)
46 csDiagram::~csDiagram()
51 void csDiagram::Redraw(wxDC
& dc
)
53 wxDiagram::Redraw(dc
);
55 // Draw line crossings
56 wxLineCrossings lineCrossings
;
57 lineCrossings
.FindCrossings(*this);
58 lineCrossings
.DrawCrossings(*this, dc
);
62 * csEvtHandler: an event handler class for all shapes
65 IMPLEMENT_DYNAMIC_CLASS(csEvtHandler
, wxShapeEvtHandler
)
67 csEvtHandler::csEvtHandler(wxShapeEvtHandler
*prev
, wxShape
*shape
, const wxString
& lab
):
68 wxShapeEvtHandler(prev
, shape
)
73 csEvtHandler::~csEvtHandler()
77 // Copy any event handler data
78 void csEvtHandler::CopyData(wxShapeEvtHandler
& copy
)
80 wxShapeEvtHandler::CopyData(copy
);
82 csEvtHandler
& csCopy
= (csEvtHandler
&) copy
;
83 csCopy
.m_label
= m_label
;
86 void csEvtHandler::OnLeftClick(double x
, double y
, int keys
, int attachment
)
88 wxClientDC
dc(GetShape()->GetCanvas());
89 GetShape()->GetCanvas()->PrepareDC(dc
);
91 csDiagramView
* view
= ((csCanvas
*)GetShape()->GetCanvas())->GetView();
92 view
->ReflectPointSize(GetShape()->GetFont()->GetPointSize());
94 if (GetShape()->IsKindOf(CLASSINFO(wxLineShape
)))
95 view
->ReflectArrowState((wxLineShape
*) GetShape());
97 csEditorToolPalette
*palette
= wxGetApp().GetDiagramPalette();
98 if (palette
->GetSelection() == PALETTE_TEXT_TOOL
)
100 view
->ReflectPointSize(GetShape()->GetFont()->GetPointSize());
104 csLabelEditingDialog
* dialog
= new csLabelEditingDialog(GetShape()->GetCanvas()->GetParent());
105 dialog
->SetShapeLabel(m_label
);
106 if (dialog
->ShowModal() == wxID_CANCEL
)
112 wxString newLabel
= dialog
->GetShapeLabel();
115 wxShape
* newShape
= GetShape()->CreateNewCopy();
117 csEvtHandler
* handler
= (csEvtHandler
*)newShape
->GetEventHandler();
118 handler
->m_label
= newLabel
;
120 view
->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Edit label", (csDiagramDocument
*) view
->GetDocument(),
121 new csCommandState(ID_CS_EDIT_PROPERTIES
, newShape
, GetShape())));
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();
132 view
->SelectAll(FALSE
);
134 selected
= !selected
;
136 GetShape()->Select(selected
, &dc
);
137 GetShape()->GetCanvas()->Redraw(dc
); // Redraw because bits of objects will be missing
139 view
->SelectShape(GetShape(), selected
);
141 else if (keys
& KEY_SHIFT
)
143 if (GetShape()->Selected())
145 GetShape()->Select(FALSE
, &dc
);
146 view
->SelectShape(GetShape(), FALSE
);
150 GetShape()->Select(TRUE
, &dc
);
151 view
->SelectShape(GetShape(), TRUE
);
153 GetShape()->GetCanvas()->Redraw(dc
); // Redraw because bits of objects will be missing
155 else if (keys
& KEY_CTRL
)
157 // Do something for CONTROL
161 ((wxFrame
*)wxGetApp().GetTopWindow())->SetStatusText(m_label
);
165 void csEvtHandler::OnRightClick(double x
, double y
, int keys
, int attachment
)
167 // Have to convert back to physical coordinates from logical coordinates.
169 int viewStartX
, viewStartY
;
171 GetShape()->GetCanvas()->GetViewStart(& viewStartX
, & viewStartY
);
172 GetShape()->GetCanvas()->GetScrollPixelsPerUnit(& unitX
, & unitY
);
174 int x1
= (int)(x
* GetShape()->GetCanvas()->GetScaleX());
175 int y1
= (int)(y
* GetShape()->GetCanvas()->GetScaleY());
177 int menuX
= (int) (x1
- (viewStartX
* unitX
)) ;
178 int menuY
= (int) (y1
- (viewStartY
* unitY
));
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
)));
184 GetShape()->GetCanvas()->PopupMenu(wxGetApp().GetShapeEditMenu(), menuX
, menuY
);
188 * Implement connection of two shapes by right-dragging between them.
191 void csEvtHandler::OnBeginDragRight(double x
, double y
, int keys
, int attachment
)
193 wxClientDC
dc(GetShape()->GetCanvas());
194 GetShape()->GetCanvas()->PrepareDC(dc
);
196 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
197 dc
.SetLogicalFunction(OGLRBLF
);
198 dc
.SetPen(dottedPen
);
200 GetShape()->GetAttachmentPositionEdge(attachment
, &xp
, &yp
);
201 dc
.DrawLine(xp
, yp
, x
, y
);
202 GetShape()->GetCanvas()->CaptureMouse();
205 void csEvtHandler::OnDragRight(bool draw
, double x
, double y
, int keys
, int attachment
)
207 wxClientDC
dc(GetShape()->GetCanvas());
208 GetShape()->GetCanvas()->PrepareDC(dc
);
210 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
211 dc
.SetLogicalFunction(OGLRBLF
);
212 dc
.SetPen(dottedPen
);
214 GetShape()->GetAttachmentPositionEdge(attachment
, &xp
, &yp
);
215 dc
.DrawLine(xp
, yp
, x
, y
);
218 void csEvtHandler::OnEndDragRight(double x
, double y
, int keys
, int attachment
)
220 GetShape()->GetCanvas()->ReleaseMouse();
221 csCanvas
*canvas
= (csCanvas
*)GetShape()->GetCanvas();
223 // Check if we're on an object
225 wxShape
*otherShape
= canvas
->FindFirstSensitiveShape(x
, y
, &new_attachment
, OP_DRAG_RIGHT
);
227 if (otherShape
&& !otherShape
->IsKindOf(CLASSINFO(wxLineShape
)))
229 wxLineShape
* theShape
= new csLineShape
;
231 theShape
->AssignNewIds();
232 theShape
->SetEventHandler(new csEvtHandler(theShape
, theShape
, wxString("")));
233 theShape
->SetPen(wxBLACK_PEN
);
234 theShape
->SetBrush(wxRED_BRUSH
);
236 wxToolBar
* toolbar
= wxGetApp().GetDiagramToolBar();
237 bool haveArrow
= toolbar
->GetToolState(DIAGRAM_TOOLBAR_LINE_ARROW
);
239 wxLineShape
*lineShape
= (wxLineShape
*)theShape
;
241 // Yes, you can have more than 2 control points, in which case
242 // it becomes a multi-segment line.
243 lineShape
->MakeLineControlPoints(2);
246 lineShape
->AddArrow(ARROW_ARROW
, ARROW_POSITION_MIDDLE
, 10.0, 0.0, "Normal arrowhead");
248 lineShape
->SetFrom(GetShape());
249 lineShape
->SetTo(otherShape
);
250 lineShape
->SetAttachments(attachment
, new_attachment
);
252 canvas
->GetView()->GetDocument()->GetCommandProcessor()->Submit(
253 new csDiagramCommand("Line", (csDiagramDocument
*)canvas
->GetView()->GetDocument(),
254 new csCommandState(ID_CS_ADD_LINE
, lineShape
, NULL
)));
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;
263 void csEvtHandler::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
265 if ((GetShape()->GetSensitivityFilter() & OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
269 if (GetShape()->GetParent())
271 GetShape()->GetParent()->HitTest(x
, y
, &attachment
, &dist
);
272 GetShape()->GetParent()->GetEventHandler()->OnDragLeft(draw
, x
, y
, keys
, attachment
);
277 wxClientDC
dc(GetShape()->GetCanvas());
278 GetShape()->GetCanvas()->PrepareDC(dc
);
280 dc
.SetLogicalFunction(OGLRBLF
);
282 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
283 dc
.SetPen(dottedPen
);
284 dc
.SetBrush(* wxTRANSPARENT_BRUSH
);
287 xx
= x
+ g_DragOffsetX
;
288 yy
= y
+ g_DragOffsetY
;
290 GetShape()->GetCanvas()->Snap(&xx
, &yy
);
292 double offsetX
= xx
- g_DragStartX
;
293 double offsetY
= yy
- g_DragStartY
;
295 // m_xpos = xx; m_ypos = yy;
297 GetShape()->GetBoundingBoxMax(&w
, &h
);
298 GetShape()->GetEventHandler()->OnDrawOutline(dc
, xx
, yy
, w
, h
);
300 // Draw bounding box for other selected shapes
301 wxNode
* node
= GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->First();
304 wxShape
* shape
= (wxShape
*) node
->Data();
305 if (shape
->Selected() && !shape
->IsKindOf(CLASSINFO(wxLineShape
)) && (shape
!= GetShape()))
307 shape
->GetBoundingBoxMax(&w
, &h
);
308 shape
->OnDrawOutline(dc
, shape
->GetX() + offsetX
, shape
->GetY() + offsetY
, w
, h
);
314 void csEvtHandler::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
316 if ((GetShape()->GetSensitivityFilter() & OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
320 if (GetShape()->GetParent())
322 GetShape()->GetParent()->HitTest(x
, y
, &attachment
, &dist
);
323 GetShape()->GetParent()->GetEventHandler()->OnBeginDragLeft(x
, y
, keys
, attachment
);
328 wxClientDC
dc(GetShape()->GetCanvas());
329 GetShape()->GetCanvas()->PrepareDC(dc
);
331 // New policy: don't erase shape until end of drag.
334 g_DragOffsetX
= GetShape()->GetX() - x
;
335 g_DragOffsetY
= GetShape()->GetY() - y
;
338 xx
= x
+ g_DragOffsetX
;
339 yy
= y
+ g_DragOffsetY
;
341 GetShape()->GetCanvas()->Snap(&xx
, &yy
);
343 g_DragStartX
= GetShape()->GetX();
344 g_DragStartY
= GetShape()->GetY();
346 double offsetX
= xx
- g_DragStartX
;
347 double offsetY
= yy
- g_DragStartY
;
349 dc
.SetLogicalFunction(OGLRBLF
);
351 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
352 dc
.SetPen(dottedPen
);
353 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
356 GetShape()->GetBoundingBoxMax(&w
, &h
);
357 GetShape()->GetEventHandler()->OnDrawOutline(dc
, xx
, yy
, w
, h
);
359 // Draw bounding box for other selected shapes
360 wxNode
* node
= GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->First();
363 wxShape
* shape
= (wxShape
*) node
->Data();
364 if (shape
->Selected() && !shape
->IsKindOf(CLASSINFO(wxLineShape
)) && (shape
!= GetShape()))
366 shape
->GetBoundingBoxMax(&w
, &h
);
367 shape
->OnDrawOutline(dc
, shape
->GetX() + offsetX
, shape
->GetY() + offsetY
, w
, h
);
372 GetShape()->GetCanvas()->CaptureMouse();
376 void csEvtHandler::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
378 csCanvas
*canvas
= (csCanvas
*)GetShape()->GetCanvas();
380 canvas
->ReleaseMouse();
381 if ((GetShape()->GetSensitivityFilter() & OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
385 if (GetShape()->GetParent())
387 GetShape()->GetParent()->HitTest(x
, y
, &attachment
, &dist
);
388 GetShape()->GetParent()->GetEventHandler()->OnEndDragLeft(x
, y
, keys
, attachment
);
393 wxClientDC
dc(canvas
);
394 canvas
->PrepareDC(dc
);
396 dc
.SetLogicalFunction(wxCOPY
);
398 double xx
= x
+ g_DragOffsetX
;
399 double yy
= y
+ g_DragOffsetY
;
401 canvas
->Snap(&xx
, &yy
);
403 double offsetX
= xx
- g_DragStartX
;
404 double offsetY
= yy
- g_DragStartY
;
406 wxShape
* newShape
= GetShape()->CreateNewCopy();
411 csDiagramCommand
* cmd
= new csDiagramCommand("Move", (csDiagramDocument
*)canvas
->GetView()->GetDocument(),
412 new csCommandState(ID_CS_MOVE
, newShape
, GetShape()));
415 wxNode
* node
= GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->First();
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())
423 wxLineShape
* lineShape
= (wxLineShape
*) shape
;
425 if (lineShape
->GetLineControlPoints()->Number() > 2)
427 wxLineShape
* newLineShape
= (wxLineShape
*) lineShape
->CreateNewCopy();
429 wxNode
*node1
= newLineShape
->GetLineControlPoints()->First();
432 wxRealPoint
*point
= (wxRealPoint
*)node1
->Data();
435 node1
= node1
->Next();
437 cmd
->AddState(new csCommandState(ID_CS_MOVE_LINE_POINT
, newLineShape
, lineShape
));
438 lineShape
->Erase(dc
);
444 // Add other selected node shapes, if any
445 node
= GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->First();
448 wxShape
* shape
= (wxShape
*) node
->Data();
449 if (shape
->Selected() && !shape
->IsKindOf(CLASSINFO(wxLineShape
)) && (shape
!= GetShape()))
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
));
459 canvas
->GetView()->GetDocument()->GetCommandProcessor()->Submit(cmd
);
462 void csEvtHandler::OnSizingEndDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int attachment
)
464 wxShape
* shape
= GetShape();
465 csCanvas
*canvas
= (csCanvas
*)GetShape()->GetCanvas();
467 if (shape
->IsKindOf(CLASSINFO(wxLineShape
)))
469 // TODO: Do/Undo support for line operations
470 ((wxLineShape
*)shape
)->wxLineShape::OnSizingEndDragLeft(pt
, x
, y
, keys
, attachment
);
472 wxLineShape
* lineShape
= (wxLineShape
*) shape
;
474 wxLineControlPoint
* lpt
= (wxLineControlPoint
*) pt
;
476 wxClientDC
dc(canvas
);
477 canvas
->PrepareDC(dc
);
479 shape
->SetDisableLabel(FALSE
);
481 if (lpt
->m_type
== CONTROL_POINT_LINE
)
483 canvas
->Snap(&x
, &y
);
485 dc
.SetLogicalFunction(wxCOPY
);
486 lpt
->SetX(x
); lpt
->SetY(y
);
487 lpt
->m_point
->x
= x
; lpt
->m_point
->y
= y
;
489 this->OnMoveLink(dc
);
491 if (lpt
->m_type
== CONTROL_POINT_ENDPOINT_FROM
)
493 if (lpt
->m_oldCursor
)
494 canvas
->SetCursor(lpt
->m_oldCursor
);
495 lineShape
->Erase(dc
);
497 lpt
->SetX(x
); lpt
->SetY(y
);
499 if (lineShape
->GetFrom())
501 lineShape
->GetFrom()->MoveLineToNewAttachment(dc
, lineShape
, x
, y
);
504 if (lpt
->m_type
== CONTROL_POINT_ENDPOINT_TO
)
506 if (lpt
->m_oldCursor
)
507 canvas
->SetCursor(lpt
->m_oldCursor
);
509 lpt
->SetX(x
); lpt
->SetY(y
);
511 if (lineShape
->GetTo())
513 lineShape
->GetTo()->MoveLineToNewAttachment(dc
, lineShape
, x
, y
);
520 wxClientDC
dc(canvas
);
521 canvas
->PrepareDC(dc
);
523 canvas
->ReleaseMouse();
524 dc
.SetLogicalFunction(wxCOPY
);
529 shape->ResetControlPoints();
530 if (!pt->m_eraseObject)
534 wxShape
* newShape
= shape
->CreateNewCopy();
536 if (newShape
->IsKindOf(CLASSINFO(wxPolygonShape
)))
538 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
539 newShape
->SetSize(ppt
->GetNewSize().x
, ppt
->GetNewSize().y
);
541 ((wxPolygonShape
*)newShape
)->CalculateBoundingBox();
542 ((wxPolygonShape
*)newShape
)->CalculatePolygonCentre();
543 newShape
->ResetControlPoints();
547 newShape
->SetSize(pt
->sm_controlPointDragEndWidth
, pt
->sm_controlPointDragEndHeight
);
548 if (shape
->GetCentreResize())
550 // Old position is fine
554 newShape
->SetX(pt
->sm_controlPointDragPosX
);
555 newShape
->SetY(pt
->sm_controlPointDragPosY
);
559 csDiagramCommand
* cmd
= new csDiagramCommand("Size", (csDiagramDocument
*)canvas
->GetView()->GetDocument(),
560 new csCommandState(ID_CS_SIZE
, newShape
, shape
));
562 canvas
->GetView()->GetDocument()->GetCommandProcessor()->Submit(cmd
);
566 void csEvtHandler::OnEndSize(double x
, double y
)
568 wxClientDC
dc(GetShape()->GetCanvas());
569 GetShape()->GetCanvas()->PrepareDC(dc
);
571 GetShape()->FormatText(dc
, m_label
);
574 void csEvtHandler::OnChangeAttachment(int attachment
, wxLineShape
* line
, wxList
& ordering
)
576 csCanvas
*canvas
= (csCanvas
*)GetShape()->GetCanvas();
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.
583 csDiagramCommand
* cmd
= new csDiagramCommand("Change attachment", (csDiagramDocument
*)canvas
->GetView()->GetDocument());
585 wxLineShape
* newLine
= (wxLineShape
*) line
->CreateNewCopy();
586 if (line
->GetTo() == GetShape())
587 newLine
->SetAttachmentTo(attachment
);
589 newLine
->SetAttachmentFrom(attachment
);
591 cmd
->AddState(new csCommandState(ID_CS_CHANGE_LINE_ATTACHMENT
, newLine
, line
));
594 wxShape
* newShape
= GetShape()->CreateNewCopy();
595 newShape
->ApplyAttachmentOrdering(ordering
);
597 cmd
->AddState(new csCommandState(ID_CS_CHANGE_LINE_ORDERING
, newShape
, GetShape()));
599 canvas
->GetView()->GetDocument()->GetCommandProcessor()->Submit(cmd
);
602 void csEvtHandler::OnLeftDoubleClick(double x
, double y
, int keys
, int attachment
)
607 // Popup up a property dialog
608 bool csEvtHandler::EditProperties()
610 wxShape
* shape
= GetShape();
612 // For now, no line property editing
613 if (shape
->IsKindOf(CLASSINFO(wxLineShape
)))
616 csDiagramView
* view
= ((csCanvas
*)shape
->GetCanvas())->GetView();
618 wxPanel
* attributeDialog
;
619 wxString attributeDialogName
;
622 if (shape
->IsKindOf(CLASSINFO(csThinRectangleShape
)))
624 attributeDialog
= new csThinRectangleDialog
;
625 attributeDialogName
= "thin_rectangle";
626 title
= "Thin Rectangle Properties";
628 else if (shape
->IsKindOf(CLASSINFO(csWideRectangleShape
)))
630 attributeDialog
= new csWideRectangleDialog
;
631 attributeDialogName
= "wide_rectangle";
632 title
= "Wide Rectangle Properties";
634 else if (shape
->IsKindOf(CLASSINFO(csTriangleShape
)))
636 attributeDialog
= new csTriangleDialog
;
637 attributeDialogName
= "triangle";
638 title
= "Triangle Properties";
640 else if (shape
->IsKindOf(CLASSINFO(csSemiCircleShape
)))
642 attributeDialog
= new csSemiCircleDialog
;
643 attributeDialogName
= "semi_circle";
644 title
= "Semicircle Properties";
646 else if (shape
->IsKindOf(CLASSINFO(csCircleShape
)))
648 attributeDialog
= new csCircleDialog
;
649 attributeDialogName
= "circle";
650 title
= "Circle Properties";
652 else if (shape
->IsKindOf(CLASSINFO(csCircleShadowShape
)))
654 attributeDialog
= new csCircleShadowDialog
;
655 attributeDialogName
= "circle_shadow";
656 title
= "Circle Shadow Properties";
658 else if (shape
->IsKindOf(CLASSINFO(csTextBoxShape
)))
660 attributeDialog
= new csTextBoxDialog
;
661 attributeDialogName
= "text_box";
662 title
= "Text Box Properties";
664 else if (shape
->IsKindOf(CLASSINFO(csGroupShape
)))
666 attributeDialog
= new csGroupDialog
;
667 attributeDialogName
= "group";
668 title
= "Group Properties";
670 else if (shape
->IsKindOf(CLASSINFO(csOctagonShape
)))
672 attributeDialog
= new csOctagonDialog
;
673 attributeDialogName
= "octagon";
674 title
= "Octagon Properties";
678 wxMessageBox("Unrecognised shape.", "Studio", wxICON_EXCLAMATION
);
682 csShapePropertiesDialog
* dialog
= new csShapePropertiesDialog(shape
->GetCanvas()->GetParent(), title
, attributeDialog
, attributeDialogName
);
683 dialog
->GetGeneralPropertiesDialog()->SetShapeLabel(m_label
);
684 if (dialog
->ShowModal() == wxID_CANCEL
)
690 wxString newLabel
= dialog
->GetGeneralPropertiesDialog()->GetShapeLabel();
693 wxShape
* newShape
= shape
->CreateNewCopy();
695 csEvtHandler
* handler2
= (csEvtHandler
*)newShape
->GetEventHandler();
696 handler2
->m_label
= newLabel
;
698 view
->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Edit properties", (csDiagramDocument
*) view
->GetDocument(),
699 new csCommandState(ID_CS_EDIT_PROPERTIES
, newShape
, shape
)));
708 bool csDiagram::OnShapeSave(wxExprDatabase
& db
, wxShape
& shape
, wxExpr
& expr
)
710 wxDiagram::OnShapeSave(db
, shape
, expr
);
711 csEvtHandler
*handler
= (csEvtHandler
*)shape
.GetEventHandler();
712 expr
.AddAttributeValueString("label", handler
->m_label
);
716 bool csDiagram::OnShapeLoad(wxExprDatabase
& db
, wxShape
& shape
, wxExpr
& expr
)
718 wxDiagram::OnShapeLoad(db
, shape
, expr
);
720 expr
.GetAttributeValue("label", label
);
721 csEvtHandler
*handler
= new csEvtHandler(&shape
, &shape
, label
);
722 shape
.SetEventHandler(handler
);
727 IMPLEMENT_DYNAMIC_CLASS(csThinRectangleShape
, wxDrawnShape
)
729 csThinRectangleShape::csThinRectangleShape()
731 SetDrawnPen(wxBLACK_PEN
);
732 wxBrush
* brush
= wxTheBrushList
->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID
);
733 SetDrawnBrush(brush
);
735 double w
= csSTANDARD_SHAPE_WIDTH
/2;
736 double h
= csSTANDARD_SHAPE_WIDTH
;
738 DrawRectangle(wxRect(- w
/2, - h
/2, w
, h
));
741 SetAttachmentMode(ATTACHMENT_MODE_BRANCHING
);
742 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
743 SetCentreResize(FALSE
);
746 IMPLEMENT_DYNAMIC_CLASS(csWideRectangleShape
, wxDrawnShape
)
748 csWideRectangleShape::csWideRectangleShape()
750 SetDrawnPen(wxBLACK_PEN
);
751 wxBrush
* brush
= wxTheBrushList
->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID
);
752 SetDrawnBrush(brush
);
754 double w
= csSTANDARD_SHAPE_WIDTH
;
757 DrawRoundedRectangle(wxRect(- w
/2, - h
/2, w
, h
), -0.3);
760 SetAttachmentMode(ATTACHMENT_MODE_BRANCHING
);
761 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
762 SetCentreResize(FALSE
);
765 IMPLEMENT_DYNAMIC_CLASS(csTriangleShape
, wxDrawnShape
)
767 csTriangleShape::csTriangleShape()
769 SetDrawnPen(wxBLACK_PEN
);
770 wxBrush
* brush
= wxTheBrushList
->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID
);
771 SetDrawnBrush(brush
);
773 double w
= csSTANDARD_SHAPE_WIDTH
;
774 double h
= (csSTANDARD_SHAPE_WIDTH
*2.0)/3.0;
776 // Triangle, from top vertex
777 wxPoint
* points
= new wxPoint
[3];
780 points
[0] = wxPoint( 0 , - h
/ 2 );
781 points
[1] = wxPoint( w
/ 2 , h
/ 2 );
782 points
[2] = wxPoint( -w
/ 2, h
/ 2 );
784 DrawPolygon(3, points
, oglMETAFLAGS_OUTLINE
);
788 // Add another triangle at the top for the black bit
789 SetDrawnBrush(wxBLACK_BRUSH
);
791 points
= new wxPoint
[3];
793 // Calculate where the new points will be, using the proportions
795 double h1
= 8; // Height of little triangle.
798 Formula: ((w/2) / h) = w1 / h1
799 w1 = ((w/2) / h) * h1;
801 double ratio
= ((w
/2.0) / h
) ;
802 double w1
= ratio
* h1
;
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
));
808 DrawPolygon(3, points
);
814 SetAttachmentMode(ATTACHMENT_MODE_BRANCHING
);
815 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
816 SetCentreResize(FALSE
);
819 IMPLEMENT_DYNAMIC_CLASS(csSemiCircleShape
, wxDrawnShape
)
821 csSemiCircleShape::csSemiCircleShape()
824 DrawAtAngle(oglDRAWN_ANGLE_0
);
826 double w
= csSTANDARD_SHAPE_WIDTH
;
829 SetDrawnPen(wxTRANSPARENT_PEN
);
830 SetDrawnBrush(wxTRANSPARENT_BRUSH
);
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)
836 DrawRectangle(wxRect(-w
/2.0, -h
/2.0, w
, h
));
838 SetDrawnPen(wxBLACK_PEN
);
839 wxBrush
* brush
= wxTheBrushList
->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID
);
840 SetDrawnBrush(brush
);
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));
849 w
= csSTANDARD_SHAPE_WIDTH
/2;
850 h
= csSTANDARD_SHAPE_WIDTH
;
852 DrawAtAngle(oglDRAWN_ANGLE_90
);
854 SetDrawnPen(wxTRANSPARENT_PEN
);
855 SetDrawnBrush(wxTRANSPARENT_BRUSH
);
857 DrawRectangle(wxRect(-w
/2, -h
/2, w
, h
));
859 SetDrawnPen(wxBLACK_PEN
);
860 SetDrawnBrush(brush
);
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));
869 DrawAtAngle(oglDRAWN_ANGLE_180
);
871 w
= csSTANDARD_SHAPE_WIDTH
;
872 h
= csSTANDARD_SHAPE_WIDTH
/2;
874 SetDrawnPen(wxTRANSPARENT_PEN
);
875 SetDrawnBrush(wxTRANSPARENT_BRUSH
);
877 DrawRectangle(wxRect(-w
/2, -h
/2, w
, h
));
879 SetDrawnPen(wxBLACK_PEN
);
880 SetDrawnBrush(brush
);
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));
889 DrawAtAngle(oglDRAWN_ANGLE_270
);
891 w
= csSTANDARD_SHAPE_WIDTH
/2;
892 h
= csSTANDARD_SHAPE_WIDTH
;
894 SetDrawnPen(wxTRANSPARENT_PEN
);
895 SetDrawnBrush(wxTRANSPARENT_BRUSH
);
897 DrawRectangle(wxRect(-w
/2, -h
/2, w
, h
));
899 SetDrawnPen(wxBLACK_PEN
);
900 SetDrawnBrush(brush
);
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));
908 DrawAtAngle(oglDRAWN_ANGLE_0
);
911 SetAttachmentMode(ATTACHMENT_MODE_BRANCHING
);
912 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
913 SetCentreResize(FALSE
);
916 IMPLEMENT_DYNAMIC_CLASS(csCircleShape
, wxCircleShape
)
918 csCircleShape::csCircleShape()
921 wxBrush
* brush
= wxTheBrushList
->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID
);
924 SetSize(csSTANDARD_SHAPE_WIDTH
*0.6, csSTANDARD_SHAPE_WIDTH
*0.6);
926 SetAttachmentMode(ATTACHMENT_MODE_BRANCHING
);
927 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
928 SetCentreResize(FALSE
);
931 IMPLEMENT_DYNAMIC_CLASS(csCircleShadowShape
, wxCircleShape
)
933 csCircleShadowShape::csCircleShadowShape()
936 wxBrush
* brush
= wxTheBrushList
->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID
);
939 SetSize(csSTANDARD_SHAPE_WIDTH
*0.6, csSTANDARD_SHAPE_WIDTH
*0.6);
941 SetAttachmentMode(ATTACHMENT_MODE_BRANCHING
);
942 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
943 SetCentreResize(FALSE
);
944 SetShadowMode(SHADOW_RIGHT
);
947 IMPLEMENT_DYNAMIC_CLASS(csOctagonShape
, wxPolygonShape
)
949 csOctagonShape::csOctagonShape()
952 SetBrush(wxTheBrushList
->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID
));
954 double w
= csSTANDARD_SHAPE_WIDTH
*0.5;
955 double h
= csSTANDARD_SHAPE_WIDTH
*0.5;
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
));
971 SetAttachmentMode(ATTACHMENT_MODE_BRANCHING
);
972 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
973 SetCentreResize(FALSE
);
976 // This is a transparent shape for drawing around other shapes.
977 IMPLEMENT_DYNAMIC_CLASS(csGroupShape
, wxRectangleShape
)
979 csGroupShape::csGroupShape()
981 SetPen(wxThePenList
->FindOrCreatePen("BLACK", 1, wxDOT
));
982 SetBrush(wxTRANSPARENT_BRUSH
);
984 SetSize(csSTANDARD_SHAPE_WIDTH
, csSTANDARD_SHAPE_WIDTH
);
985 SetCentreResize(FALSE
);
988 void csGroupShape::OnDraw(wxDC
& dc
)
990 wxRectangleShape::OnDraw(dc
);
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
)
999 double width
= 0.0, height
= 0.0;
1000 GetBoundingBoxMin(&width
, &height
);
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);
1007 double edgeTolerance
= 4.0;
1009 // Test each edge in turn
1012 if (x
>= x1
&& x
<= x2
)
1014 if ((y
>= y1
- edgeTolerance
) && (y
<= y1
+ edgeTolerance
))
1016 if ((y
<= y2
+ edgeTolerance
) && (y
>= y2
- edgeTolerance
))
1020 if (y
>= y1
&& y
<= y2
)
1022 if ((x
>= x1
- edgeTolerance
) && (x
<= x1
+ edgeTolerance
))
1024 if ((x
<= x2
+ edgeTolerance
) && (x
>= x2
- edgeTolerance
))
1031 IMPLEMENT_DYNAMIC_CLASS(csTextBoxShape
, wxRectangleShape
)
1033 csTextBoxShape::csTextBoxShape()
1035 SetPen(wxTRANSPARENT_PEN
);
1036 SetBrush(wxTRANSPARENT_BRUSH
);
1038 SetSize(csSTANDARD_SHAPE_WIDTH
, csSTANDARD_SHAPE_WIDTH
/2.0);
1040 SetAttachmentMode(ATTACHMENT_MODE_NONE
);
1041 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
1042 SetCentreResize(FALSE
);
1045 IMPLEMENT_DYNAMIC_CLASS(csLineShape
, wxLineShape
)
1047 csLineShape::csLineShape()
1051 bool csLineShape::OnMoveMiddleControlPoint(wxDC
& dc
, wxLineControlPoint
* lpt
, const wxRealPoint
& pt
)
1053 csDiagramView
* view
= ((csCanvas
*)GetCanvas())->GetView();
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
;
1059 wxLineShape
* newShape
= (wxLineShape
*) this->CreateNewCopy();
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
;
1065 view
->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Move line point", (csDiagramDocument
*) view
->GetDocument(),
1066 new csCommandState(ID_CS_MOVE_LINE_POINT
, newShape
, this)));
1071 wxLabelShape
* csLineShape::OnCreateLabelShape(wxLineShape
*parent
, wxShapeRegion
*region
, double w
, double h
)
1073 return new csLabelShape(parent
, region
, w
, h
);
1077 bool csLineShape::OnLabelMovePre(wxDC
& dc
, wxLabelShape
* labelShape
, double x
, double y
, double old_x
, double old_y
, bool display
)
1079 csDiagramView
* view
= ((csCanvas
*)GetCanvas())->GetView();
1081 wxLineShape
* newShape
= (wxLineShape
*) this->CreateNewCopy();
1083 wxLineShape::OnLabelMovePre(dc
, labelShape
, x
, y
, old_x
, old_y
, display
);
1085 view
->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Move label", (csDiagramDocument
*) view
->GetDocument(),
1086 new csCommandState(ID_CS_MOVE_LABEL
, newShape
, this)));
1091 IMPLEMENT_DYNAMIC_CLASS(csLabelShape
, wxLabelShape
)
1093 csLabelShape::csLabelShape(wxLineShape
*parent
, wxShapeRegion
*region
, double w
, double h
):
1094 wxLabelShape(parent
, region
, w
, h
)
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
)
1102 wxLabelShape::OnEndDragLeft(x
, y
, keys
, attachment
);
1106 // Menu for editing shapes
1107 void studioShapeEditProc(wxMenu
& menu
, wxCommandEvent
& event
)
1109 wxShape
* shape
= (wxShape
*) menu
.GetClientData();
1110 csDiagramView
* view
= ((csCanvas
*)shape
->GetCanvas())->GetView();
1112 switch (event
.GetId())
1114 case ID_CS_EDIT_PROPERTIES
:
1116 csEvtHandler
* handler1
= (csEvtHandler
*)shape
->GetEventHandler();
1117 handler1
->EditProperties();
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
)
1128 wxString newLabel
= dialog
->GetShapeLabel();
1131 wxShape
* newShape
= shape
->CreateNewCopy();
1133 csEvtHandler
* handler2
= (csEvtHandler
*)newShape
->GetEventHandler();
1134 handler2
->m_label
= newLabel
;
1136 view
->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Edit label", (csDiagramDocument
*) view
->GetDocument(),
1137 new csCommandState(ID_CS_EDIT_LABEL
, newShape
, shape
)));
1148 case ID_CS_ROTATE_CLOCKWISE
:
1149 case ID_CS_ROTATE_ANTICLOCKWISE
:
1151 if (shape
->IsKindOf(CLASSINFO(wxLineShape
)))
1154 double theta
= shape
->GetRotation();
1155 const double myPi
= 3.1415926535897932384626433832795 ;
1156 double ninetyDegrees
= myPi
/2.0;
1159 if (event
.GetId() == ID_CS_ROTATE_CLOCKWISE
)
1161 theta
+= ninetyDegrees
;
1162 opStr
= "Rotate clockwise";
1166 theta
-= ninetyDegrees
;
1167 opStr
= "Rotate anticlockwise";
1170 if (theta
>= 2.0*myPi
|| theta
< 0.0)
1172 wxShape
* newShape
= shape
->CreateNewCopy();
1173 newShape
->Rotate(0.0, 0.0, theta
);
1176 newShapes
.Append(newShape
);
1177 oldShapes
.Append(shape
);
1178 view
->DoCmd(newShapes
, oldShapes
, event
.GetId(), opStr
);
1186 BEGIN_EVENT_TABLE(ShapeEditMenu
, wxMenu
)
1187 EVT_COMMAND_RANGE(1, 65000, wxEVT_COMMAND_MENU_SELECTED
, ShapeEditMenu::OnCommand
)
1190 void ShapeEditMenu::OnCommand(wxCommandEvent
& event
)
1192 studioShapeEditProc(*this, event
);