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/ogl/ogl.h> // base header of OGL, includes and adjusts wx/deprecated/setup.h
37 #include "cspalette.h"
40 #define csSTANDARD_SHAPE_WIDTH 100
42 IMPLEMENT_CLASS(csDiagram
, wxDiagram
)
44 csDiagram::~csDiagram()
49 void csDiagram::Redraw(wxDC
& dc
)
51 wxDiagram::Redraw(dc
);
53 // Draw line crossings
54 wxLineCrossings lineCrossings
;
55 lineCrossings
.FindCrossings(*this);
56 lineCrossings
.DrawCrossings(*this, dc
);
60 * csEvtHandler: an event handler class for all shapes
63 IMPLEMENT_DYNAMIC_CLASS(csEvtHandler
, wxShapeEvtHandler
)
65 csEvtHandler::csEvtHandler(wxShapeEvtHandler
*prev
, wxShape
*shape
, const wxString
& lab
):
66 wxShapeEvtHandler(prev
, shape
)
71 csEvtHandler::~csEvtHandler()
75 // Copy any event handler data
76 void csEvtHandler::CopyData(wxShapeEvtHandler
& copy
)
78 wxShapeEvtHandler::CopyData(copy
);
80 csEvtHandler
& csCopy
= (csEvtHandler
&) copy
;
81 csCopy
.m_label
= m_label
;
84 void csEvtHandler::OnLeftClick(double WXUNUSED(x
), double WXUNUSED(y
), int keys
, int WXUNUSED(attachment
))
86 wxClientDC
dc(GetShape()->GetCanvas());
87 GetShape()->GetCanvas()->PrepareDC(dc
);
89 csDiagramView
* view
= ((csCanvas
*)GetShape()->GetCanvas())->GetView();
90 view
->ReflectPointSize(GetShape()->GetFont()->GetPointSize());
92 if (GetShape()->IsKindOf(CLASSINFO(wxLineShape
)))
93 view
->ReflectArrowState((wxLineShape
*) GetShape());
95 csEditorToolPalette
*palette
= wxGetApp().GetDiagramPalette();
96 if (palette
->GetSelection() == PALETTE_TEXT_TOOL
)
98 view
->ReflectPointSize(GetShape()->GetFont()->GetPointSize());
102 csLabelEditingDialog
* dialog
= new csLabelEditingDialog(GetShape()->GetCanvas()->GetParent());
103 dialog
->SetShapeLabel(m_label
);
104 if (dialog
->ShowModal() == wxID_CANCEL
)
110 wxString newLabel
= dialog
->GetShapeLabel();
113 wxShape
* newShape
= GetShape()->CreateNewCopy();
115 csEvtHandler
* handler
= (csEvtHandler
*)newShape
->GetEventHandler();
116 handler
->m_label
= newLabel
;
118 view
->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Edit label", (csDiagramDocument
*) view
->GetDocument(),
119 new csCommandState(ID_CS_EDIT_PROPERTIES
, newShape
, GetShape())));
126 // If no shift key, then everything is deselected.
127 // If the shape was selected, deselect it and vice versa.
128 bool selected
= GetShape()->Selected();
130 view
->SelectAll(false);
132 selected
= !selected
;
134 GetShape()->Select(selected
, &dc
);
135 GetShape()->GetCanvas()->Redraw(dc
); // Redraw because bits of objects will be missing
137 view
->SelectShape(GetShape(), selected
);
139 else if (keys
& KEY_SHIFT
)
141 if (GetShape()->Selected())
143 GetShape()->Select(false, &dc
);
144 view
->SelectShape(GetShape(), false);
148 GetShape()->Select(true, &dc
);
149 view
->SelectShape(GetShape(), true);
151 GetShape()->GetCanvas()->Redraw(dc
); // Redraw because bits of objects will be missing
153 else if (keys
& KEY_CTRL
)
155 // Do something for CONTROL
160 ((wxFrame
*)wxGetApp().GetTopWindow())->SetStatusText(m_label
);
161 #endif // wxUSE_STATUSBAR
165 void csEvtHandler::OnRightClick(double x
, double y
, int WXUNUSED(keys
), int WXUNUSED(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 WXUNUSED(keys
), int attachment
)
193 wxClientDC
dc(GetShape()->GetCanvas());
194 GetShape()->GetCanvas()->PrepareDC(dc
);
196 wxPen
dottedPen(*wxBLACK
, 1, wxDOT
);
197 dc
.SetLogicalFunction(OGLRBLF
);
198 dc
.SetPen(dottedPen
);
200 GetShape()->GetAttachmentPositionEdge(attachment
, &xp
, &yp
);
201 dc
.DrawLine((wxCoord
)xp
, (wxCoord
)yp
, (wxCoord
)x
, (wxCoord
)y
);
202 GetShape()->GetCanvas()->CaptureMouse();
205 void csEvtHandler::OnDragRight(bool WXUNUSED(draw
), double x
, double y
, int WXUNUSED(keys
), int attachment
)
207 wxClientDC
dc(GetShape()->GetCanvas());
208 GetShape()->GetCanvas()->PrepareDC(dc
);
210 wxPen
dottedPen(*wxBLACK
, 1, wxDOT
);
211 dc
.SetLogicalFunction(OGLRBLF
);
212 dc
.SetPen(dottedPen
);
214 GetShape()->GetAttachmentPositionEdge(attachment
, &xp
, &yp
);
215 dc
.DrawLine((wxCoord
)xp
, (wxCoord
)yp
, (wxCoord
)x
, (wxCoord
)y
);
218 void csEvtHandler::OnEndDragRight(double x
, double y
, int WXUNUSED(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
, wxEmptyString
));
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, _T("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(_T("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(*wxBLACK
, 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 wxObjectList::compatibility_iterator node
= GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->GetFirst();
304 wxShape
* shape
= (wxShape
*) node
->GetData();
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
);
310 node
= node
->GetNext();
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(*wxBLACK
, 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 wxObjectList::compatibility_iterator node
= GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->GetFirst();
363 wxShape
* shape
= (wxShape
*) node
->GetData();
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
);
369 node
= node
->GetNext();
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(_T("Move"), (csDiagramDocument
*)canvas
->GetView()->GetDocument(),
412 new csCommandState(ID_CS_MOVE
, newShape
, GetShape()));
415 wxObjectList::compatibility_iterator node
= GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->GetFirst();
418 wxShape
* shape
= (wxShape
*) node
->GetData();
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()->GetCount() > 2)
427 wxLineShape
* newLineShape
= (wxLineShape
*) lineShape
->CreateNewCopy();
429 wxObjectList::compatibility_iterator node1
= newLineShape
->GetLineControlPoints()->GetFirst();
432 wxRealPoint
*point
= (wxRealPoint
*)node1
->GetData();
435 node1
= node1
->GetNext();
437 cmd
->AddState(new csCommandState(ID_CS_MOVE_LINE_POINT
, newLineShape
, lineShape
));
438 lineShape
->Erase(dc
);
441 node
= node
->GetNext();
444 // Add other selected node shapes, if any
445 node
= GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->GetFirst();
448 wxShape
* shape
= (wxShape
*) node
->GetData();
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
));
456 node
= node
->GetNext();
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(_T("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 WXUNUSED(x
), double WXUNUSED(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(_T("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 WXUNUSED(x
), double WXUNUSED(y
), int WXUNUSED(keys
), int WXUNUSED(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
= _T("thin_rectangle");
626 title
= _T("Thin Rectangle Properties");
628 else if (shape
->IsKindOf(CLASSINFO(csWideRectangleShape
)))
630 attributeDialog
= new csWideRectangleDialog
;
631 attributeDialogName
= _T("wide_rectangle");
632 title
= _T("Wide Rectangle Properties");
634 else if (shape
->IsKindOf(CLASSINFO(csTriangleShape
)))
636 attributeDialog
= new csTriangleDialog
;
637 attributeDialogName
= _T("triangle");
638 title
= _T("Triangle Properties");
640 else if (shape
->IsKindOf(CLASSINFO(csSemiCircleShape
)))
642 attributeDialog
= new csSemiCircleDialog
;
643 attributeDialogName
= _T("semi_circle");
644 title
= _T("Semicircle Properties");
646 else if (shape
->IsKindOf(CLASSINFO(csCircleShape
)))
648 attributeDialog
= new csCircleDialog
;
649 attributeDialogName
= _T("circle");
650 title
= _T("Circle Properties");
652 else if (shape
->IsKindOf(CLASSINFO(csCircleShadowShape
)))
654 attributeDialog
= new csCircleShadowDialog
;
655 attributeDialogName
= _T("circle_shadow");
656 title
= _T("Circle Shadow Properties");
658 else if (shape
->IsKindOf(CLASSINFO(csTextBoxShape
)))
660 attributeDialog
= new csTextBoxDialog
;
661 attributeDialogName
= _T("text_box");
662 title
= _T("Text Box Properties");
664 else if (shape
->IsKindOf(CLASSINFO(csGroupShape
)))
666 attributeDialog
= new csGroupDialog
;
667 attributeDialogName
= _T("group");
668 title
= _T("Group Properties");
670 else if (shape
->IsKindOf(CLASSINFO(csOctagonShape
)))
672 attributeDialog
= new csOctagonDialog
;
673 attributeDialogName
= _T("octagon");
674 title
= _T("Octagon Properties");
678 wxMessageBox(_T("Unrecognised shape."), _T("Studio"), wxICON_EXCLAMATION
);
682 wxString
newLabel(m_label
);
684 #if wxUSE_WX_RESOURCES
685 csShapePropertiesDialog
* dialog
= new csShapePropertiesDialog(shape
->GetCanvas()->GetParent(), title
, attributeDialog
, attributeDialogName
);
686 dialog
->GetGeneralPropertiesDialog()->SetShapeLabel(m_label
);
687 if (dialog
->ShowModal() == wxID_CANCEL
)
693 newLabel
= dialog
->GetGeneralPropertiesDialog()->GetShapeLabel();
696 wxUnusedVar(attributeDialog
);
697 #endif // wxUSE_WX_RESOURCES
699 wxShape
* newShape
= shape
->CreateNewCopy();
701 csEvtHandler
* handler2
= (csEvtHandler
*)newShape
->GetEventHandler();
702 handler2
->m_label
= newLabel
;
704 view
->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand(_T("Edit properties"), (csDiagramDocument
*) view
->GetDocument(),
705 new csCommandState(ID_CS_EDIT_PROPERTIES
, newShape
, shape
)));
715 bool csDiagram::OnShapeSave(wxExprDatabase
& db
, wxShape
& shape
, wxExpr
& expr
)
717 wxDiagram::OnShapeSave(db
, shape
, expr
);
718 csEvtHandler
*handler
= (csEvtHandler
*)shape
.GetEventHandler();
719 expr
.AddAttributeValueString(_T("label"), handler
->m_label
);
723 bool csDiagram::OnShapeLoad(wxExprDatabase
& db
, wxShape
& shape
, wxExpr
& expr
)
725 wxDiagram::OnShapeLoad(db
, shape
, expr
);
726 wxString label
= wxEmptyString
;
727 expr
.GetAttributeValue(_T("label"), label
);
728 csEvtHandler
*handler
= new csEvtHandler(&shape
, &shape
, label
);
729 shape
.SetEventHandler(handler
);
733 #endif // wxUSE_PROLOGIO
735 IMPLEMENT_DYNAMIC_CLASS(csThinRectangleShape
, wxDrawnShape
)
737 csThinRectangleShape::csThinRectangleShape()
739 SetDrawnPen(wxBLACK_PEN
);
740 wxBrush
* brush
= wxTheBrushList
->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID
);
741 SetDrawnBrush(brush
);
743 double w
= csSTANDARD_SHAPE_WIDTH
/2;
744 double h
= csSTANDARD_SHAPE_WIDTH
;
746 DrawRectangle(wxRect((int)(- w
/2), (int)(- h
/2), (int)(w
), (int)(h
)));
749 SetAttachmentMode(ATTACHMENT_MODE_BRANCHING
);
750 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
751 SetCentreResize(false);
754 IMPLEMENT_DYNAMIC_CLASS(csWideRectangleShape
, wxDrawnShape
)
756 csWideRectangleShape::csWideRectangleShape()
758 SetDrawnPen(wxBLACK_PEN
);
759 wxBrush
* brush
= wxTheBrushList
->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID
);
760 SetDrawnBrush(brush
);
762 double w
= csSTANDARD_SHAPE_WIDTH
;
765 DrawRoundedRectangle(wxRect((int)(- w
/2), (int)(- h
/2), (int)(w
), (int)(h
)), -0.3);
768 SetAttachmentMode(ATTACHMENT_MODE_BRANCHING
);
769 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
770 SetCentreResize(false);
773 IMPLEMENT_DYNAMIC_CLASS(csTriangleShape
, wxDrawnShape
)
775 csTriangleShape::csTriangleShape()
777 SetDrawnPen(wxBLACK_PEN
);
778 wxBrush
* brush
= wxTheBrushList
->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID
);
779 SetDrawnBrush(brush
);
781 double w
= csSTANDARD_SHAPE_WIDTH
;
782 double h
= (csSTANDARD_SHAPE_WIDTH
*2.0)/3.0;
784 // Triangle, from top vertex
785 wxPoint
* points
= new wxPoint
[3];
788 points
[0] = wxPoint( 0 , (int)(- h
/ 2) );
789 points
[1] = wxPoint( (int)(w
/ 2) , (int)(h
/ 2) );
790 points
[2] = wxPoint( (int)(-w
/ 2), (int)(h
/ 2) );
792 DrawPolygon(3, points
, oglMETAFLAGS_OUTLINE
);
796 // Add another triangle at the top for the black bit
797 SetDrawnBrush(wxBLACK_BRUSH
);
799 points
= new wxPoint
[3];
801 // Calculate where the new points will be, using the proportions
803 double h1
= 8; // Height of little triangle.
806 Formula: ((w/2) / h) = w1 / h1
807 w1 = ((w/2) / h) * h1;
809 double ratio
= ((w
/2.0) / h
) ;
810 double w1
= ratio
* h1
;
812 points
[0] = wxPoint(0 , (int) (- h
/ 2 ));
813 points
[1] = wxPoint( (int) w1
, (int) (- h
/ 2 + h1
));
814 points
[2] = wxPoint( (int) -w1
, (int) (- h
/ 2 + h1
));
816 DrawPolygon(3, points
);
822 SetAttachmentMode(ATTACHMENT_MODE_BRANCHING
);
823 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
824 SetCentreResize(false);
827 IMPLEMENT_DYNAMIC_CLASS(csSemiCircleShape
, wxDrawnShape
)
829 csSemiCircleShape::csSemiCircleShape()
832 DrawAtAngle(oglDRAWN_ANGLE_0
);
834 double w
= csSTANDARD_SHAPE_WIDTH
;
837 SetDrawnPen(wxTRANSPARENT_PEN
);
838 SetDrawnBrush(wxTRANSPARENT_BRUSH
);
840 // Draw a dummy rectangle that will be used for calculating the
841 // bounding box, since we can't calculate the bounding box for
842 // an arbitrary arc (not implemented)
844 DrawRectangle(wxRect((int)(-w
/2.0), (int)(-h
/2.0), (int)(w
), (int)(h
)));
846 SetDrawnPen(wxBLACK_PEN
);
847 wxBrush
* brush
= wxTheBrushList
->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID
);
848 SetDrawnBrush(brush
);
850 DrawEllipticArc(wxRect((int)(-w
/2), (int)(-h
/2), (int)(w
), (int)(2*h
)), 0.0, 180.0);
851 DrawLine(wxPoint((int)(-w
/2), (int)(h
/2)), wxPoint((int)(w
/2), (int)(h
/2)));
857 w
= csSTANDARD_SHAPE_WIDTH
/2;
858 h
= csSTANDARD_SHAPE_WIDTH
;
860 DrawAtAngle(oglDRAWN_ANGLE_90
);
862 SetDrawnPen(wxTRANSPARENT_PEN
);
863 SetDrawnBrush(wxTRANSPARENT_BRUSH
);
865 DrawRectangle(wxRect((int)(-w
/2), (int)(-h
/2), (int)(w
), (int)(h
)));
867 SetDrawnPen(wxBLACK_PEN
);
868 SetDrawnBrush(brush
);
870 DrawEllipticArc(wxRect((int)(-w
/2 - w
), (int)(-h
/2), (int)(2*w
), (int)(h
)), 270.0, 90.0);
871 DrawLine(wxPoint((int)(-w
/2), (int)(-h
/2)), wxPoint((int)(-w
/2), (int)(h
/2)));
877 DrawAtAngle(oglDRAWN_ANGLE_180
);
879 w
= csSTANDARD_SHAPE_WIDTH
;
880 h
= csSTANDARD_SHAPE_WIDTH
/2;
882 SetDrawnPen(wxTRANSPARENT_PEN
);
883 SetDrawnBrush(wxTRANSPARENT_BRUSH
);
885 DrawRectangle(wxRect((int)(-w
/2), (int)(-h
/2), (int)(w
), (int)(h
)));
887 SetDrawnPen(wxBLACK_PEN
);
888 SetDrawnBrush(brush
);
890 DrawEllipticArc(wxRect((int)(-w
/2), (int)(-h
/2 - h
), (int)(w
), (int)(2*h
)), 180.0, 0.0);
891 DrawLine(wxPoint((int)(-w
/2), (int)(-h
/2)), wxPoint((int)(w
/2), (int)(-h
/2)));
897 DrawAtAngle(oglDRAWN_ANGLE_270
);
899 w
= csSTANDARD_SHAPE_WIDTH
/2;
900 h
= csSTANDARD_SHAPE_WIDTH
;
902 SetDrawnPen(wxTRANSPARENT_PEN
);
903 SetDrawnBrush(wxTRANSPARENT_BRUSH
);
905 DrawRectangle(wxRect((int)(-w
/2), (int)(-h
/2), (int)(w
), (int)(h
)));
907 SetDrawnPen(wxBLACK_PEN
);
908 SetDrawnBrush(brush
);
910 DrawEllipticArc(wxRect((int)(-w
/2), (int)(-h
/2), (int)(2*w
), (int)(h
)), 90.0, 270.0);
911 DrawLine(wxPoint((int)(w
/2),(int)(-h
/2)), wxPoint((int)(w
/2), (int)(h
/2)));
916 DrawAtAngle(oglDRAWN_ANGLE_0
);
919 SetAttachmentMode(ATTACHMENT_MODE_BRANCHING
);
920 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
921 SetCentreResize(false);
924 IMPLEMENT_DYNAMIC_CLASS(csCircleShape
, wxCircleShape
)
926 csCircleShape::csCircleShape()
929 wxBrush
* brush
= wxTheBrushList
->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID
);
932 SetSize(csSTANDARD_SHAPE_WIDTH
*0.6, csSTANDARD_SHAPE_WIDTH
*0.6);
934 SetAttachmentMode(ATTACHMENT_MODE_BRANCHING
);
935 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
936 SetCentreResize(false);
939 IMPLEMENT_DYNAMIC_CLASS(csCircleShadowShape
, wxCircleShape
)
941 csCircleShadowShape::csCircleShadowShape()
944 wxBrush
* brush
= wxTheBrushList
->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID
);
947 SetSize(csSTANDARD_SHAPE_WIDTH
*0.6, csSTANDARD_SHAPE_WIDTH
*0.6);
949 SetAttachmentMode(ATTACHMENT_MODE_BRANCHING
);
950 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
951 SetCentreResize(false);
952 SetShadowMode(SHADOW_RIGHT
);
955 IMPLEMENT_DYNAMIC_CLASS(csOctagonShape
, wxPolygonShape
)
957 csOctagonShape::csOctagonShape()
960 SetBrush(wxTheBrushList
->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID
));
962 double w
= csSTANDARD_SHAPE_WIDTH
*0.5;
963 double h
= csSTANDARD_SHAPE_WIDTH
*0.5;
967 wxList
* points
= new wxList
;
968 points
->Append((wxObject
*) new wxRealPoint(-w
/2.0 + prop
, -h
/2.0));
969 points
->Append((wxObject
*) new wxRealPoint(w
/2.0 - prop
, -h
/2.0));
970 points
->Append((wxObject
*) new wxRealPoint(w
/2.0, -h
/2.0 + prop
));
971 points
->Append((wxObject
*) new wxRealPoint(w
/2.0, h
/2.0 - prop
));
972 points
->Append((wxObject
*) new wxRealPoint(w
/2.0 - prop
, h
/2.0));
973 points
->Append((wxObject
*) new wxRealPoint(-w
/2.0 + prop
, h
/2.0));
974 points
->Append((wxObject
*) new wxRealPoint(-w
/2.0, h
/2.0 - prop
));
975 points
->Append((wxObject
*) new wxRealPoint(-w
/2.0, -h
/2.0 + prop
));
979 SetAttachmentMode(ATTACHMENT_MODE_BRANCHING
);
980 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
981 SetCentreResize(false);
984 // This is a transparent shape for drawing around other shapes.
985 IMPLEMENT_DYNAMIC_CLASS(csGroupShape
, wxRectangleShape
)
987 csGroupShape::csGroupShape()
989 SetPen(wxThePenList
->FindOrCreatePen(_T("BLACK"), 1, wxDOT
));
990 SetBrush(wxTRANSPARENT_BRUSH
);
992 SetSize(csSTANDARD_SHAPE_WIDTH
, csSTANDARD_SHAPE_WIDTH
);
993 SetCentreResize(false);
996 void csGroupShape::OnDraw(wxDC
& dc
)
998 wxRectangleShape::OnDraw(dc
);
1001 // Must modify the hit-test so it doesn't obscure shapes that are inside.
1002 bool csGroupShape::HitTest(double x
, double y
, int* attachment
, double* distance
)
1007 double width
= 0.0, height
= 0.0;
1008 GetBoundingBoxMin(&width
, &height
);
1010 double x1
= GetX() - (width
/2.0);
1011 double y1
= GetY() - (height
/2.0);
1012 double x2
= GetX() + (width
/2.0);
1013 double y2
= GetY() + (height
/2.0);
1015 double edgeTolerance
= 4.0;
1017 // Test each edge in turn
1020 if (x
>= x1
&& x
<= x2
)
1022 if ((y
>= y1
- edgeTolerance
) && (y
<= y1
+ edgeTolerance
))
1024 if ((y
<= y2
+ edgeTolerance
) && (y
>= y2
- edgeTolerance
))
1028 if (y
>= y1
&& y
<= y2
)
1030 if ((x
>= x1
- edgeTolerance
) && (x
<= x1
+ edgeTolerance
))
1032 if ((x
<= x2
+ edgeTolerance
) && (x
>= x2
- edgeTolerance
))
1039 IMPLEMENT_DYNAMIC_CLASS(csTextBoxShape
, wxRectangleShape
)
1041 csTextBoxShape::csTextBoxShape()
1043 SetPen(wxTRANSPARENT_PEN
);
1044 SetBrush(wxTRANSPARENT_BRUSH
);
1046 SetSize(csSTANDARD_SHAPE_WIDTH
, csSTANDARD_SHAPE_WIDTH
/2.0);
1048 SetAttachmentMode(ATTACHMENT_MODE_NONE
);
1049 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
1050 SetCentreResize(false);
1053 IMPLEMENT_DYNAMIC_CLASS(csLineShape
, wxLineShape
)
1055 csLineShape::csLineShape()
1059 bool csLineShape::OnMoveMiddleControlPoint(wxDC
& WXUNUSED(dc
), wxLineControlPoint
* lpt
, const wxRealPoint
& pt
)
1061 csDiagramView
* view
= ((csCanvas
*)GetCanvas())->GetView();
1063 // Temporarily set the new shape properties so we can copy it
1064 lpt
->SetX(pt
.x
); lpt
->SetY(pt
.y
);
1065 lpt
->m_point
->x
= pt
.x
; lpt
->m_point
->y
= pt
.y
;
1067 wxLineShape
* newShape
= (wxLineShape
*) this->CreateNewCopy();
1069 // Now set them back again
1070 lpt
->SetX(lpt
->m_originalPos
.x
); lpt
->SetY(lpt
->m_originalPos
.y
);
1071 lpt
->m_point
->x
= lpt
->m_originalPos
.x
; lpt
->m_point
->y
= lpt
->m_originalPos
.y
;
1073 view
->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand(_T("Move line point"), (csDiagramDocument
*) view
->GetDocument(),
1074 new csCommandState(ID_CS_MOVE_LINE_POINT
, newShape
, this)));
1079 wxLabelShape
* csLineShape::OnCreateLabelShape(wxLineShape
*parent
, wxShapeRegion
*region
, double w
, double h
)
1081 return new csLabelShape(parent
, region
, w
, h
);
1085 bool csLineShape::OnLabelMovePre(wxDC
& dc
, wxLabelShape
* labelShape
, double x
, double y
, double old_x
, double old_y
, bool display
)
1087 csDiagramView
* view
= ((csCanvas
*)GetCanvas())->GetView();
1089 wxLineShape
* newShape
= (wxLineShape
*) this->CreateNewCopy();
1091 wxLineShape::OnLabelMovePre(dc
, labelShape
, x
, y
, old_x
, old_y
, display
);
1093 view
->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Move label", (csDiagramDocument
*) view
->GetDocument(),
1094 new csCommandState(ID_CS_MOVE_LABEL
, newShape
, this)));
1099 IMPLEMENT_DYNAMIC_CLASS(csLabelShape
, wxLabelShape
)
1101 csLabelShape::csLabelShape(wxLineShape
*parent
, wxShapeRegion
*region
, double w
, double h
):
1102 wxLabelShape(parent
, region
, w
, h
)
1106 // TODO: not sure how intercept normal behaviour (OnMovePre) to make
1107 // label movement undo-able.
1108 void csLabelShape::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
1110 wxLabelShape::OnEndDragLeft(x
, y
, keys
, attachment
);
1114 // Menu for editing shapes
1115 void studioShapeEditProc(wxMenu
& menu
, wxCommandEvent
& event
)
1117 wxShape
* shape
= (wxShape
*) menu
.GetClientData();
1118 csDiagramView
* view
= ((csCanvas
*)shape
->GetCanvas())->GetView();
1120 switch (event
.GetId())
1122 case ID_CS_EDIT_PROPERTIES
:
1124 csEvtHandler
* handler1
= (csEvtHandler
*)shape
->GetEventHandler();
1125 handler1
->EditProperties();
1127 csEvtHandler
* handler1
= (csEvtHandler
*)shape
->GetEventHandler();
1128 csLabelEditingDialog
* dialog
= new csLabelEditingDialog(shape
->GetCanvas()->GetParent());
1129 dialog
->SetShapeLabel(handler1
->m_label
);
1130 if (dialog
->ShowModal() == wxID_CANCEL
)
1136 wxString newLabel
= dialog
->GetShapeLabel();
1139 wxShape
* newShape
= shape
->CreateNewCopy();
1141 csEvtHandler
* handler2
= (csEvtHandler
*)newShape
->GetEventHandler();
1142 handler2
->m_label
= newLabel
;
1144 view
->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Edit label", (csDiagramDocument
*) view
->GetDocument(),
1145 new csCommandState(ID_CS_EDIT_LABEL
, newShape
, shape
)));
1156 case ID_CS_ROTATE_CLOCKWISE
:
1157 case ID_CS_ROTATE_ANTICLOCKWISE
:
1159 if (shape
->IsKindOf(CLASSINFO(wxLineShape
)))
1162 double theta
= shape
->GetRotation();
1163 const double myPi
= M_PI
;
1164 double ninetyDegrees
= myPi
/2.0;
1167 if (event
.GetId() == ID_CS_ROTATE_CLOCKWISE
)
1169 theta
+= ninetyDegrees
;
1170 opStr
= _T("Rotate clockwise");
1174 theta
-= ninetyDegrees
;
1175 opStr
= _T("Rotate anticlockwise");
1178 if (theta
>= 2.0*myPi
|| theta
< 0.0)
1180 wxShape
* newShape
= shape
->CreateNewCopy();
1181 newShape
->Rotate(0.0, 0.0, theta
);
1184 newShapes
.Append(newShape
);
1185 oldShapes
.Append(shape
);
1186 view
->DoCmd(newShapes
, oldShapes
, event
.GetId(), opStr
);
1194 BEGIN_EVENT_TABLE(ShapeEditMenu
, wxMenu
)
1195 EVT_COMMAND_RANGE(1, 65000, wxEVT_COMMAND_MENU_SELECTED
, ShapeEditMenu::OnCommand
)
1198 void ShapeEditMenu::OnCommand(wxCommandEvent
& event
)
1200 studioShapeEditProc(*this, event
);