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/deprecated/setup.h>
32 #include <wx/deprecated/wxexpr.h>
38 #include <wx/ogl/basicp.h>
39 #include <wx/ogl/linesp.h>
40 #include "cspalette.h"
43 #define csSTANDARD_SHAPE_WIDTH 100
45 IMPLEMENT_CLASS(csDiagram
, wxDiagram
)
47 csDiagram::~csDiagram()
52 void csDiagram::Redraw(wxDC
& dc
)
54 wxDiagram::Redraw(dc
);
56 // Draw line crossings
57 wxLineCrossings lineCrossings
;
58 lineCrossings
.FindCrossings(*this);
59 lineCrossings
.DrawCrossings(*this, dc
);
63 * csEvtHandler: an event handler class for all shapes
66 IMPLEMENT_DYNAMIC_CLASS(csEvtHandler
, wxShapeEvtHandler
)
68 csEvtHandler::csEvtHandler(wxShapeEvtHandler
*prev
, wxShape
*shape
, const wxString
& lab
):
69 wxShapeEvtHandler(prev
, shape
)
74 csEvtHandler::~csEvtHandler()
78 // Copy any event handler data
79 void csEvtHandler::CopyData(wxShapeEvtHandler
& copy
)
81 wxShapeEvtHandler::CopyData(copy
);
83 csEvtHandler
& csCopy
= (csEvtHandler
&) copy
;
84 csCopy
.m_label
= m_label
;
87 void csEvtHandler::OnLeftClick(double WXUNUSED(x
), double WXUNUSED(y
), int keys
, int WXUNUSED(attachment
))
89 wxClientDC
dc(GetShape()->GetCanvas());
90 GetShape()->GetCanvas()->PrepareDC(dc
);
92 csDiagramView
* view
= ((csCanvas
*)GetShape()->GetCanvas())->GetView();
93 view
->ReflectPointSize(GetShape()->GetFont()->GetPointSize());
95 if (GetShape()->IsKindOf(CLASSINFO(wxLineShape
)))
96 view
->ReflectArrowState((wxLineShape
*) GetShape());
98 csEditorToolPalette
*palette
= wxGetApp().GetDiagramPalette();
99 if (palette
->GetSelection() == PALETTE_TEXT_TOOL
)
101 view
->ReflectPointSize(GetShape()->GetFont()->GetPointSize());
105 csLabelEditingDialog
* dialog
= new csLabelEditingDialog(GetShape()->GetCanvas()->GetParent());
106 dialog
->SetShapeLabel(m_label
);
107 if (dialog
->ShowModal() == wxID_CANCEL
)
113 wxString newLabel
= dialog
->GetShapeLabel();
116 wxShape
* newShape
= GetShape()->CreateNewCopy();
118 csEvtHandler
* handler
= (csEvtHandler
*)newShape
->GetEventHandler();
119 handler
->m_label
= newLabel
;
121 view
->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Edit label", (csDiagramDocument
*) view
->GetDocument(),
122 new csCommandState(ID_CS_EDIT_PROPERTIES
, newShape
, GetShape())));
129 // If no shift key, then everything is deselected.
130 // If the shape was selected, deselect it and vice versa.
131 bool selected
= GetShape()->Selected();
133 view
->SelectAll(false);
135 selected
= !selected
;
137 GetShape()->Select(selected
, &dc
);
138 GetShape()->GetCanvas()->Redraw(dc
); // Redraw because bits of objects will be missing
140 view
->SelectShape(GetShape(), selected
);
142 else if (keys
& KEY_SHIFT
)
144 if (GetShape()->Selected())
146 GetShape()->Select(false, &dc
);
147 view
->SelectShape(GetShape(), false);
151 GetShape()->Select(true, &dc
);
152 view
->SelectShape(GetShape(), true);
154 GetShape()->GetCanvas()->Redraw(dc
); // Redraw because bits of objects will be missing
156 else if (keys
& KEY_CTRL
)
158 // Do something for CONTROL
162 ((wxFrame
*)wxGetApp().GetTopWindow())->SetStatusText(m_label
);
166 void csEvtHandler::OnRightClick(double x
, double y
, int WXUNUSED(keys
), int WXUNUSED(attachment
))
168 // Have to convert back to physical coordinates from logical coordinates.
170 int viewStartX
, viewStartY
;
172 GetShape()->GetCanvas()->GetViewStart(& viewStartX
, & viewStartY
);
173 GetShape()->GetCanvas()->GetScrollPixelsPerUnit(& unitX
, & unitY
);
175 int x1
= (int)(x
* GetShape()->GetCanvas()->GetScaleX());
176 int y1
= (int)(y
* GetShape()->GetCanvas()->GetScaleY());
178 int menuX
= (int) (x1
- (viewStartX
* unitX
)) ;
179 int menuY
= (int) (y1
- (viewStartY
* unitY
));
181 wxGetApp().GetShapeEditMenu()->SetClientData((char*) GetShape());
182 wxGetApp().GetShapeEditMenu()->Enable(ID_CS_ROTATE_CLOCKWISE
, !GetShape()->IsKindOf(CLASSINFO(wxLineShape
)));
183 wxGetApp().GetShapeEditMenu()->Enable(ID_CS_ROTATE_ANTICLOCKWISE
, !GetShape()->IsKindOf(CLASSINFO(wxLineShape
)));
185 GetShape()->GetCanvas()->PopupMenu(wxGetApp().GetShapeEditMenu(), menuX
, menuY
);
189 * Implement connection of two shapes by right-dragging between them.
192 void csEvtHandler::OnBeginDragRight(double x
, double y
, int WXUNUSED(keys
), int attachment
)
194 wxClientDC
dc(GetShape()->GetCanvas());
195 GetShape()->GetCanvas()->PrepareDC(dc
);
197 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
198 dc
.SetLogicalFunction(OGLRBLF
);
199 dc
.SetPen(dottedPen
);
201 GetShape()->GetAttachmentPositionEdge(attachment
, &xp
, &yp
);
202 dc
.DrawLine((wxCoord
)xp
, (wxCoord
)yp
, (wxCoord
)x
, (wxCoord
)y
);
203 GetShape()->GetCanvas()->CaptureMouse();
206 void csEvtHandler::OnDragRight(bool WXUNUSED(draw
), double x
, double y
, int WXUNUSED(keys
), int attachment
)
208 wxClientDC
dc(GetShape()->GetCanvas());
209 GetShape()->GetCanvas()->PrepareDC(dc
);
211 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
212 dc
.SetLogicalFunction(OGLRBLF
);
213 dc
.SetPen(dottedPen
);
215 GetShape()->GetAttachmentPositionEdge(attachment
, &xp
, &yp
);
216 dc
.DrawLine((wxCoord
)xp
, (wxCoord
)yp
, (wxCoord
)x
, (wxCoord
)y
);
219 void csEvtHandler::OnEndDragRight(double x
, double y
, int WXUNUSED(keys
), int attachment
)
221 GetShape()->GetCanvas()->ReleaseMouse();
222 csCanvas
*canvas
= (csCanvas
*)GetShape()->GetCanvas();
224 // Check if we're on an object
226 wxShape
*otherShape
= canvas
->FindFirstSensitiveShape(x
, y
, &new_attachment
, OP_DRAG_RIGHT
);
228 if (otherShape
&& !otherShape
->IsKindOf(CLASSINFO(wxLineShape
)))
230 wxLineShape
* theShape
= new csLineShape
;
232 theShape
->AssignNewIds();
233 theShape
->SetEventHandler(new csEvtHandler(theShape
, theShape
, wxEmptyString
));
234 theShape
->SetPen(wxBLACK_PEN
);
235 theShape
->SetBrush(wxRED_BRUSH
);
237 wxToolBar
* toolbar
= wxGetApp().GetDiagramToolBar();
238 bool haveArrow
= toolbar
->GetToolState(DIAGRAM_TOOLBAR_LINE_ARROW
);
240 wxLineShape
*lineShape
= (wxLineShape
*)theShape
;
242 // Yes, you can have more than 2 control points, in which case
243 // it becomes a multi-segment line.
244 lineShape
->MakeLineControlPoints(2);
247 lineShape
->AddArrow(ARROW_ARROW
, ARROW_POSITION_MIDDLE
, 10.0, 0.0, _T("Normal arrowhead"));
249 lineShape
->SetFrom(GetShape());
250 lineShape
->SetTo(otherShape
);
251 lineShape
->SetAttachments(attachment
, new_attachment
);
253 canvas
->GetView()->GetDocument()->GetCommandProcessor()->Submit(
254 new csDiagramCommand(_T("Line"), (csDiagramDocument
*)canvas
->GetView()->GetDocument(),
255 new csCommandState(ID_CS_ADD_LINE
, lineShape
, NULL
)));
259 static double g_DragOffsetX
= 0.0;
260 static double g_DragOffsetY
= 0.0;
261 static double g_DragStartX
= 0.0;
262 static double g_DragStartY
= 0.0;
264 void csEvtHandler::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
266 if ((GetShape()->GetSensitivityFilter() & OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
270 if (GetShape()->GetParent())
272 GetShape()->GetParent()->HitTest(x
, y
, &attachment
, &dist
);
273 GetShape()->GetParent()->GetEventHandler()->OnDragLeft(draw
, x
, y
, keys
, attachment
);
278 wxClientDC
dc(GetShape()->GetCanvas());
279 GetShape()->GetCanvas()->PrepareDC(dc
);
281 dc
.SetLogicalFunction(OGLRBLF
);
283 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
284 dc
.SetPen(dottedPen
);
285 dc
.SetBrush(* wxTRANSPARENT_BRUSH
);
288 xx
= x
+ g_DragOffsetX
;
289 yy
= y
+ g_DragOffsetY
;
291 GetShape()->GetCanvas()->Snap(&xx
, &yy
);
293 double offsetX
= xx
- g_DragStartX
;
294 double offsetY
= yy
- g_DragStartY
;
296 // m_xpos = xx; m_ypos = yy;
298 GetShape()->GetBoundingBoxMax(&w
, &h
);
299 GetShape()->GetEventHandler()->OnDrawOutline(dc
, xx
, yy
, w
, h
);
301 // Draw bounding box for other selected shapes
302 wxNode
* node
= GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->GetFirst();
305 wxShape
* shape
= (wxShape
*) node
->GetData();
306 if (shape
->Selected() && !shape
->IsKindOf(CLASSINFO(wxLineShape
)) && (shape
!= GetShape()))
308 shape
->GetBoundingBoxMax(&w
, &h
);
309 shape
->OnDrawOutline(dc
, shape
->GetX() + offsetX
, shape
->GetY() + offsetY
, w
, h
);
311 node
= node
->GetNext();
315 void csEvtHandler::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
317 if ((GetShape()->GetSensitivityFilter() & OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
321 if (GetShape()->GetParent())
323 GetShape()->GetParent()->HitTest(x
, y
, &attachment
, &dist
);
324 GetShape()->GetParent()->GetEventHandler()->OnBeginDragLeft(x
, y
, keys
, attachment
);
329 wxClientDC
dc(GetShape()->GetCanvas());
330 GetShape()->GetCanvas()->PrepareDC(dc
);
332 // New policy: don't erase shape until end of drag.
335 g_DragOffsetX
= GetShape()->GetX() - x
;
336 g_DragOffsetY
= GetShape()->GetY() - y
;
339 xx
= x
+ g_DragOffsetX
;
340 yy
= y
+ g_DragOffsetY
;
342 GetShape()->GetCanvas()->Snap(&xx
, &yy
);
344 g_DragStartX
= GetShape()->GetX();
345 g_DragStartY
= GetShape()->GetY();
347 double offsetX
= xx
- g_DragStartX
;
348 double offsetY
= yy
- g_DragStartY
;
350 dc
.SetLogicalFunction(OGLRBLF
);
352 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
353 dc
.SetPen(dottedPen
);
354 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
357 GetShape()->GetBoundingBoxMax(&w
, &h
);
358 GetShape()->GetEventHandler()->OnDrawOutline(dc
, xx
, yy
, w
, h
);
360 // Draw bounding box for other selected shapes
361 wxNode
* node
= GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->GetFirst();
364 wxShape
* shape
= (wxShape
*) node
->GetData();
365 if (shape
->Selected() && !shape
->IsKindOf(CLASSINFO(wxLineShape
)) && (shape
!= GetShape()))
367 shape
->GetBoundingBoxMax(&w
, &h
);
368 shape
->OnDrawOutline(dc
, shape
->GetX() + offsetX
, shape
->GetY() + offsetY
, w
, h
);
370 node
= node
->GetNext();
373 GetShape()->GetCanvas()->CaptureMouse();
377 void csEvtHandler::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
379 csCanvas
*canvas
= (csCanvas
*)GetShape()->GetCanvas();
381 canvas
->ReleaseMouse();
382 if ((GetShape()->GetSensitivityFilter() & OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
386 if (GetShape()->GetParent())
388 GetShape()->GetParent()->HitTest(x
, y
, &attachment
, &dist
);
389 GetShape()->GetParent()->GetEventHandler()->OnEndDragLeft(x
, y
, keys
, attachment
);
394 wxClientDC
dc(canvas
);
395 canvas
->PrepareDC(dc
);
397 dc
.SetLogicalFunction(wxCOPY
);
399 double xx
= x
+ g_DragOffsetX
;
400 double yy
= y
+ g_DragOffsetY
;
402 canvas
->Snap(&xx
, &yy
);
404 double offsetX
= xx
- g_DragStartX
;
405 double offsetY
= yy
- g_DragStartY
;
407 wxShape
* newShape
= GetShape()->CreateNewCopy();
412 csDiagramCommand
* cmd
= new csDiagramCommand(_T("Move"), (csDiagramDocument
*)canvas
->GetView()->GetDocument(),
413 new csCommandState(ID_CS_MOVE
, newShape
, GetShape()));
416 wxNode
* node
= GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->GetFirst();
419 wxShape
* shape
= (wxShape
*) node
->GetData();
420 // Only move the line point(s) if both ends move too
421 if (shape
->IsKindOf(CLASSINFO(wxLineShape
)) &&
422 ((wxLineShape
*)shape
)->GetTo()->Selected() && ((wxLineShape
*)shape
)->GetFrom()->Selected())
424 wxLineShape
* lineShape
= (wxLineShape
*) shape
;
426 if (lineShape
->GetLineControlPoints()->GetCount() > 2)
428 wxLineShape
* newLineShape
= (wxLineShape
*) lineShape
->CreateNewCopy();
430 wxNode
*node1
= newLineShape
->GetLineControlPoints()->GetFirst();
433 wxRealPoint
*point
= (wxRealPoint
*)node1
->GetData();
436 node1
= node1
->GetNext();
438 cmd
->AddState(new csCommandState(ID_CS_MOVE_LINE_POINT
, newLineShape
, lineShape
));
439 lineShape
->Erase(dc
);
442 node
= node
->GetNext();
445 // Add other selected node shapes, if any
446 node
= GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->GetFirst();
449 wxShape
* shape
= (wxShape
*) node
->GetData();
450 if (shape
->Selected() && !shape
->IsKindOf(CLASSINFO(wxLineShape
)) && (shape
!= GetShape()))
452 wxShape
* newShape2
= shape
->CreateNewCopy();
453 newShape2
->SetX(shape
->GetX() + offsetX
);
454 newShape2
->SetY(shape
->GetY() + offsetY
);
455 cmd
->AddState(new csCommandState(ID_CS_MOVE
, newShape2
, shape
));
457 node
= node
->GetNext();
460 canvas
->GetView()->GetDocument()->GetCommandProcessor()->Submit(cmd
);
463 void csEvtHandler::OnSizingEndDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int attachment
)
465 wxShape
* shape
= GetShape();
466 csCanvas
*canvas
= (csCanvas
*)GetShape()->GetCanvas();
468 if (shape
->IsKindOf(CLASSINFO(wxLineShape
)))
470 // TODO: Do/Undo support for line operations
471 ((wxLineShape
*)shape
)->wxLineShape::OnSizingEndDragLeft(pt
, x
, y
, keys
, attachment
);
473 wxLineShape
* lineShape
= (wxLineShape
*) shape
;
475 wxLineControlPoint
* lpt
= (wxLineControlPoint
*) pt
;
477 wxClientDC
dc(canvas
);
478 canvas
->PrepareDC(dc
);
480 shape
->SetDisableLabel(false);
482 if (lpt
->m_type
== CONTROL_POINT_LINE
)
484 canvas
->Snap(&x
, &y
);
486 dc
.SetLogicalFunction(wxCOPY
);
487 lpt
->SetX(x
); lpt
->SetY(y
);
488 lpt
->m_point
->x
= x
; lpt
->m_point
->y
= y
;
490 this->OnMoveLink(dc
);
492 if (lpt
->m_type
== CONTROL_POINT_ENDPOINT_FROM
)
494 if (lpt
->m_oldCursor
)
495 canvas
->SetCursor(lpt
->m_oldCursor
);
496 lineShape
->Erase(dc
);
498 lpt
->SetX(x
); lpt
->SetY(y
);
500 if (lineShape
->GetFrom())
502 lineShape
->GetFrom()->MoveLineToNewAttachment(dc
, lineShape
, x
, y
);
505 if (lpt
->m_type
== CONTROL_POINT_ENDPOINT_TO
)
507 if (lpt
->m_oldCursor
)
508 canvas
->SetCursor(lpt
->m_oldCursor
);
510 lpt
->SetX(x
); lpt
->SetY(y
);
512 if (lineShape
->GetTo())
514 lineShape
->GetTo()->MoveLineToNewAttachment(dc
, lineShape
, x
, y
);
521 wxClientDC
dc(canvas
);
522 canvas
->PrepareDC(dc
);
524 canvas
->ReleaseMouse();
525 dc
.SetLogicalFunction(wxCOPY
);
530 shape->ResetControlPoints();
531 if (!pt->m_eraseObject)
535 wxShape
* newShape
= shape
->CreateNewCopy();
537 if (newShape
->IsKindOf(CLASSINFO(wxPolygonShape
)))
539 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
540 newShape
->SetSize(ppt
->GetNewSize().x
, ppt
->GetNewSize().y
);
542 ((wxPolygonShape
*)newShape
)->CalculateBoundingBox();
543 ((wxPolygonShape
*)newShape
)->CalculatePolygonCentre();
544 newShape
->ResetControlPoints();
548 newShape
->SetSize(pt
->sm_controlPointDragEndWidth
, pt
->sm_controlPointDragEndHeight
);
549 if (shape
->GetCentreResize())
551 // Old position is fine
555 newShape
->SetX(pt
->sm_controlPointDragPosX
);
556 newShape
->SetY(pt
->sm_controlPointDragPosY
);
560 csDiagramCommand
* cmd
= new csDiagramCommand(_T("Size"), (csDiagramDocument
*)canvas
->GetView()->GetDocument(),
561 new csCommandState(ID_CS_SIZE
, newShape
, shape
));
563 canvas
->GetView()->GetDocument()->GetCommandProcessor()->Submit(cmd
);
567 void csEvtHandler::OnEndSize(double WXUNUSED(x
), double WXUNUSED(y
))
569 wxClientDC
dc(GetShape()->GetCanvas());
570 GetShape()->GetCanvas()->PrepareDC(dc
);
572 GetShape()->FormatText(dc
, m_label
);
575 void csEvtHandler::OnChangeAttachment(int attachment
, wxLineShape
* line
, wxList
& ordering
)
577 csCanvas
*canvas
= (csCanvas
*)GetShape()->GetCanvas();
579 // We actually submit two different states: one to change the ordering, and another
580 // to change the attachment for the line.
581 // Problem. If we refresh after the attachment change, we'll get a flicker.
582 // We really want to do both in a oner.
584 csDiagramCommand
* cmd
= new csDiagramCommand(_T("Change attachment"), (csDiagramDocument
*)canvas
->GetView()->GetDocument());
586 wxLineShape
* newLine
= (wxLineShape
*) line
->CreateNewCopy();
587 if (line
->GetTo() == GetShape())
588 newLine
->SetAttachmentTo(attachment
);
590 newLine
->SetAttachmentFrom(attachment
);
592 cmd
->AddState(new csCommandState(ID_CS_CHANGE_LINE_ATTACHMENT
, newLine
, line
));
595 wxShape
* newShape
= GetShape()->CreateNewCopy();
596 newShape
->ApplyAttachmentOrdering(ordering
);
598 cmd
->AddState(new csCommandState(ID_CS_CHANGE_LINE_ORDERING
, newShape
, GetShape()));
600 canvas
->GetView()->GetDocument()->GetCommandProcessor()->Submit(cmd
);
603 void csEvtHandler::OnLeftDoubleClick(double WXUNUSED(x
), double WXUNUSED(y
), int WXUNUSED(keys
), int WXUNUSED(attachment
))
608 // Popup up a property dialog
609 bool csEvtHandler::EditProperties()
611 wxShape
* shape
= GetShape();
613 // For now, no line property editing
614 if (shape
->IsKindOf(CLASSINFO(wxLineShape
)))
617 csDiagramView
* view
= ((csCanvas
*)shape
->GetCanvas())->GetView();
619 wxPanel
* attributeDialog
;
620 wxString attributeDialogName
;
623 if (shape
->IsKindOf(CLASSINFO(csThinRectangleShape
)))
625 attributeDialog
= new csThinRectangleDialog
;
626 attributeDialogName
= _T("thin_rectangle");
627 title
= _T("Thin Rectangle Properties");
629 else if (shape
->IsKindOf(CLASSINFO(csWideRectangleShape
)))
631 attributeDialog
= new csWideRectangleDialog
;
632 attributeDialogName
= _T("wide_rectangle");
633 title
= _T("Wide Rectangle Properties");
635 else if (shape
->IsKindOf(CLASSINFO(csTriangleShape
)))
637 attributeDialog
= new csTriangleDialog
;
638 attributeDialogName
= _T("triangle");
639 title
= _T("Triangle Properties");
641 else if (shape
->IsKindOf(CLASSINFO(csSemiCircleShape
)))
643 attributeDialog
= new csSemiCircleDialog
;
644 attributeDialogName
= _T("semi_circle");
645 title
= _T("Semicircle Properties");
647 else if (shape
->IsKindOf(CLASSINFO(csCircleShape
)))
649 attributeDialog
= new csCircleDialog
;
650 attributeDialogName
= _T("circle");
651 title
= _T("Circle Properties");
653 else if (shape
->IsKindOf(CLASSINFO(csCircleShadowShape
)))
655 attributeDialog
= new csCircleShadowDialog
;
656 attributeDialogName
= _T("circle_shadow");
657 title
= _T("Circle Shadow Properties");
659 else if (shape
->IsKindOf(CLASSINFO(csTextBoxShape
)))
661 attributeDialog
= new csTextBoxDialog
;
662 attributeDialogName
= _T("text_box");
663 title
= _T("Text Box Properties");
665 else if (shape
->IsKindOf(CLASSINFO(csGroupShape
)))
667 attributeDialog
= new csGroupDialog
;
668 attributeDialogName
= _T("group");
669 title
= _T("Group Properties");
671 else if (shape
->IsKindOf(CLASSINFO(csOctagonShape
)))
673 attributeDialog
= new csOctagonDialog
;
674 attributeDialogName
= _T("octagon");
675 title
= _T("Octagon Properties");
679 wxMessageBox(_T("Unrecognised shape."), _T("Studio"), wxICON_EXCLAMATION
);
683 csShapePropertiesDialog
* dialog
= new csShapePropertiesDialog(shape
->GetCanvas()->GetParent(), title
, attributeDialog
, attributeDialogName
);
684 dialog
->GetGeneralPropertiesDialog()->SetShapeLabel(m_label
);
685 if (dialog
->ShowModal() == wxID_CANCEL
)
691 wxString newLabel
= dialog
->GetGeneralPropertiesDialog()->GetShapeLabel();
694 wxShape
* newShape
= shape
->CreateNewCopy();
696 csEvtHandler
* handler2
= (csEvtHandler
*)newShape
->GetEventHandler();
697 handler2
->m_label
= newLabel
;
699 view
->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand(_T("Edit properties"), (csDiagramDocument
*) view
->GetDocument(),
700 new csCommandState(ID_CS_EDIT_PROPERTIES
, newShape
, shape
)));
709 bool csDiagram::OnShapeSave(wxExprDatabase
& db
, wxShape
& shape
, wxExpr
& expr
)
711 wxDiagram::OnShapeSave(db
, shape
, expr
);
712 csEvtHandler
*handler
= (csEvtHandler
*)shape
.GetEventHandler();
713 expr
.AddAttributeValueString(_T("label"), handler
->m_label
);
717 bool csDiagram::OnShapeLoad(wxExprDatabase
& db
, wxShape
& shape
, wxExpr
& expr
)
719 wxDiagram::OnShapeLoad(db
, shape
, expr
);
720 wxString label
= wxEmptyString
;
721 expr
.GetAttributeValue(_T("label"), label
);
722 csEvtHandler
*handler
= new csEvtHandler(&shape
, &shape
, label
);
723 shape
.SetEventHandler(handler
);
728 IMPLEMENT_DYNAMIC_CLASS(csThinRectangleShape
, wxDrawnShape
)
730 csThinRectangleShape::csThinRectangleShape()
732 SetDrawnPen(wxBLACK_PEN
);
733 wxBrush
* brush
= wxTheBrushList
->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID
);
734 SetDrawnBrush(brush
);
736 double w
= csSTANDARD_SHAPE_WIDTH
/2;
737 double h
= csSTANDARD_SHAPE_WIDTH
;
739 DrawRectangle(wxRect((int)(- w
/2), (int)(- h
/2), (int)(w
), (int)(h
)));
742 SetAttachmentMode(ATTACHMENT_MODE_BRANCHING
);
743 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
744 SetCentreResize(false);
747 IMPLEMENT_DYNAMIC_CLASS(csWideRectangleShape
, wxDrawnShape
)
749 csWideRectangleShape::csWideRectangleShape()
751 SetDrawnPen(wxBLACK_PEN
);
752 wxBrush
* brush
= wxTheBrushList
->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID
);
753 SetDrawnBrush(brush
);
755 double w
= csSTANDARD_SHAPE_WIDTH
;
758 DrawRoundedRectangle(wxRect((int)(- w
/2), (int)(- h
/2), (int)(w
), (int)(h
)), -0.3);
761 SetAttachmentMode(ATTACHMENT_MODE_BRANCHING
);
762 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
763 SetCentreResize(false);
766 IMPLEMENT_DYNAMIC_CLASS(csTriangleShape
, wxDrawnShape
)
768 csTriangleShape::csTriangleShape()
770 SetDrawnPen(wxBLACK_PEN
);
771 wxBrush
* brush
= wxTheBrushList
->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID
);
772 SetDrawnBrush(brush
);
774 double w
= csSTANDARD_SHAPE_WIDTH
;
775 double h
= (csSTANDARD_SHAPE_WIDTH
*2.0)/3.0;
777 // Triangle, from top vertex
778 wxPoint
* points
= new wxPoint
[3];
781 points
[0] = wxPoint( 0 , (int)(- h
/ 2) );
782 points
[1] = wxPoint( (int)(w
/ 2) , (int)(h
/ 2) );
783 points
[2] = wxPoint( (int)(-w
/ 2), (int)(h
/ 2) );
785 DrawPolygon(3, points
, oglMETAFLAGS_OUTLINE
);
789 // Add another triangle at the top for the black bit
790 SetDrawnBrush(wxBLACK_BRUSH
);
792 points
= new wxPoint
[3];
794 // Calculate where the new points will be, using the proportions
796 double h1
= 8; // Height of little triangle.
799 Formula: ((w/2) / h) = w1 / h1
800 w1 = ((w/2) / h) * h1;
802 double ratio
= ((w
/2.0) / h
) ;
803 double w1
= ratio
* h1
;
805 points
[0] = wxPoint(0 , (int) (- h
/ 2 ));
806 points
[1] = wxPoint( (int) w1
, (int) (- h
/ 2 + h1
));
807 points
[2] = wxPoint( (int) -w1
, (int) (- h
/ 2 + h1
));
809 DrawPolygon(3, points
);
815 SetAttachmentMode(ATTACHMENT_MODE_BRANCHING
);
816 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
817 SetCentreResize(false);
820 IMPLEMENT_DYNAMIC_CLASS(csSemiCircleShape
, wxDrawnShape
)
822 csSemiCircleShape::csSemiCircleShape()
825 DrawAtAngle(oglDRAWN_ANGLE_0
);
827 double w
= csSTANDARD_SHAPE_WIDTH
;
830 SetDrawnPen(wxTRANSPARENT_PEN
);
831 SetDrawnBrush(wxTRANSPARENT_BRUSH
);
833 // Draw a dummy rectangle that will be used for calculating the
834 // bounding box, since we can't calculate the bounding box for
835 // an arbitrary arc (not implemented)
837 DrawRectangle(wxRect((int)(-w
/2.0), (int)(-h
/2.0), (int)(w
), (int)(h
)));
839 SetDrawnPen(wxBLACK_PEN
);
840 wxBrush
* brush
= wxTheBrushList
->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID
);
841 SetDrawnBrush(brush
);
843 DrawEllipticArc(wxRect((int)(-w
/2), (int)(-h
/2), (int)(w
), (int)(2*h
)), 0.0, 180.0);
844 DrawLine(wxPoint((int)(-w
/2), (int)(h
/2)), wxPoint((int)(w
/2), (int)(h
/2)));
850 w
= csSTANDARD_SHAPE_WIDTH
/2;
851 h
= csSTANDARD_SHAPE_WIDTH
;
853 DrawAtAngle(oglDRAWN_ANGLE_90
);
855 SetDrawnPen(wxTRANSPARENT_PEN
);
856 SetDrawnBrush(wxTRANSPARENT_BRUSH
);
858 DrawRectangle(wxRect((int)(-w
/2), (int)(-h
/2), (int)(w
), (int)(h
)));
860 SetDrawnPen(wxBLACK_PEN
);
861 SetDrawnBrush(brush
);
863 DrawEllipticArc(wxRect((int)(-w
/2 - w
), (int)(-h
/2), (int)(2*w
), (int)(h
)), 270.0, 90.0);
864 DrawLine(wxPoint((int)(-w
/2), (int)(-h
/2)), wxPoint((int)(-w
/2), (int)(h
/2)));
870 DrawAtAngle(oglDRAWN_ANGLE_180
);
872 w
= csSTANDARD_SHAPE_WIDTH
;
873 h
= csSTANDARD_SHAPE_WIDTH
/2;
875 SetDrawnPen(wxTRANSPARENT_PEN
);
876 SetDrawnBrush(wxTRANSPARENT_BRUSH
);
878 DrawRectangle(wxRect((int)(-w
/2), (int)(-h
/2), (int)(w
), (int)(h
)));
880 SetDrawnPen(wxBLACK_PEN
);
881 SetDrawnBrush(brush
);
883 DrawEllipticArc(wxRect((int)(-w
/2), (int)(-h
/2 - h
), (int)(w
), (int)(2*h
)), 180.0, 0.0);
884 DrawLine(wxPoint((int)(-w
/2), (int)(-h
/2)), wxPoint((int)(w
/2), (int)(-h
/2)));
890 DrawAtAngle(oglDRAWN_ANGLE_270
);
892 w
= csSTANDARD_SHAPE_WIDTH
/2;
893 h
= csSTANDARD_SHAPE_WIDTH
;
895 SetDrawnPen(wxTRANSPARENT_PEN
);
896 SetDrawnBrush(wxTRANSPARENT_BRUSH
);
898 DrawRectangle(wxRect((int)(-w
/2), (int)(-h
/2), (int)(w
), (int)(h
)));
900 SetDrawnPen(wxBLACK_PEN
);
901 SetDrawnBrush(brush
);
903 DrawEllipticArc(wxRect((int)(-w
/2), (int)(-h
/2), (int)(2*w
), (int)(h
)), 90.0, 270.0);
904 DrawLine(wxPoint((int)(w
/2),(int)(-h
/2)), wxPoint((int)(w
/2), (int)(h
/2)));
909 DrawAtAngle(oglDRAWN_ANGLE_0
);
912 SetAttachmentMode(ATTACHMENT_MODE_BRANCHING
);
913 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
914 SetCentreResize(false);
917 IMPLEMENT_DYNAMIC_CLASS(csCircleShape
, wxCircleShape
)
919 csCircleShape::csCircleShape()
922 wxBrush
* brush
= wxTheBrushList
->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID
);
925 SetSize(csSTANDARD_SHAPE_WIDTH
*0.6, csSTANDARD_SHAPE_WIDTH
*0.6);
927 SetAttachmentMode(ATTACHMENT_MODE_BRANCHING
);
928 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
929 SetCentreResize(false);
932 IMPLEMENT_DYNAMIC_CLASS(csCircleShadowShape
, wxCircleShape
)
934 csCircleShadowShape::csCircleShadowShape()
937 wxBrush
* brush
= wxTheBrushList
->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID
);
940 SetSize(csSTANDARD_SHAPE_WIDTH
*0.6, csSTANDARD_SHAPE_WIDTH
*0.6);
942 SetAttachmentMode(ATTACHMENT_MODE_BRANCHING
);
943 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
944 SetCentreResize(false);
945 SetShadowMode(SHADOW_RIGHT
);
948 IMPLEMENT_DYNAMIC_CLASS(csOctagonShape
, wxPolygonShape
)
950 csOctagonShape::csOctagonShape()
953 SetBrush(wxTheBrushList
->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID
));
955 double w
= csSTANDARD_SHAPE_WIDTH
*0.5;
956 double h
= csSTANDARD_SHAPE_WIDTH
*0.5;
960 wxList
* points
= new wxList
;
961 points
->Append((wxObject
*) new wxRealPoint(-w
/2.0 + prop
, -h
/2.0));
962 points
->Append((wxObject
*) new wxRealPoint(w
/2.0 - prop
, -h
/2.0));
963 points
->Append((wxObject
*) new wxRealPoint(w
/2.0, -h
/2.0 + prop
));
964 points
->Append((wxObject
*) new wxRealPoint(w
/2.0, h
/2.0 - prop
));
965 points
->Append((wxObject
*) new wxRealPoint(w
/2.0 - prop
, h
/2.0));
966 points
->Append((wxObject
*) new wxRealPoint(-w
/2.0 + prop
, h
/2.0));
967 points
->Append((wxObject
*) new wxRealPoint(-w
/2.0, h
/2.0 - prop
));
968 points
->Append((wxObject
*) new wxRealPoint(-w
/2.0, -h
/2.0 + prop
));
972 SetAttachmentMode(ATTACHMENT_MODE_BRANCHING
);
973 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
974 SetCentreResize(false);
977 // This is a transparent shape for drawing around other shapes.
978 IMPLEMENT_DYNAMIC_CLASS(csGroupShape
, wxRectangleShape
)
980 csGroupShape::csGroupShape()
982 SetPen(wxThePenList
->FindOrCreatePen(_T("BLACK"), 1, wxDOT
));
983 SetBrush(wxTRANSPARENT_BRUSH
);
985 SetSize(csSTANDARD_SHAPE_WIDTH
, csSTANDARD_SHAPE_WIDTH
);
986 SetCentreResize(false);
989 void csGroupShape::OnDraw(wxDC
& dc
)
991 wxRectangleShape::OnDraw(dc
);
994 // Must modify the hit-test so it doesn't obscure shapes that are inside.
995 bool csGroupShape::HitTest(double x
, double y
, int* attachment
, double* distance
)
1000 double width
= 0.0, height
= 0.0;
1001 GetBoundingBoxMin(&width
, &height
);
1003 double x1
= GetX() - (width
/2.0);
1004 double y1
= GetY() - (height
/2.0);
1005 double x2
= GetX() + (width
/2.0);
1006 double y2
= GetY() + (height
/2.0);
1008 double edgeTolerance
= 4.0;
1010 // Test each edge in turn
1013 if (x
>= x1
&& x
<= x2
)
1015 if ((y
>= y1
- edgeTolerance
) && (y
<= y1
+ edgeTolerance
))
1017 if ((y
<= y2
+ edgeTolerance
) && (y
>= y2
- edgeTolerance
))
1021 if (y
>= y1
&& y
<= y2
)
1023 if ((x
>= x1
- edgeTolerance
) && (x
<= x1
+ edgeTolerance
))
1025 if ((x
<= x2
+ edgeTolerance
) && (x
>= x2
- edgeTolerance
))
1032 IMPLEMENT_DYNAMIC_CLASS(csTextBoxShape
, wxRectangleShape
)
1034 csTextBoxShape::csTextBoxShape()
1036 SetPen(wxTRANSPARENT_PEN
);
1037 SetBrush(wxTRANSPARENT_BRUSH
);
1039 SetSize(csSTANDARD_SHAPE_WIDTH
, csSTANDARD_SHAPE_WIDTH
/2.0);
1041 SetAttachmentMode(ATTACHMENT_MODE_NONE
);
1042 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
1043 SetCentreResize(false);
1046 IMPLEMENT_DYNAMIC_CLASS(csLineShape
, wxLineShape
)
1048 csLineShape::csLineShape()
1052 bool csLineShape::OnMoveMiddleControlPoint(wxDC
& WXUNUSED(dc
), wxLineControlPoint
* lpt
, const wxRealPoint
& pt
)
1054 csDiagramView
* view
= ((csCanvas
*)GetCanvas())->GetView();
1056 // Temporarily set the new shape properties so we can copy it
1057 lpt
->SetX(pt
.x
); lpt
->SetY(pt
.y
);
1058 lpt
->m_point
->x
= pt
.x
; lpt
->m_point
->y
= pt
.y
;
1060 wxLineShape
* newShape
= (wxLineShape
*) this->CreateNewCopy();
1062 // Now set them back again
1063 lpt
->SetX(lpt
->m_originalPos
.x
); lpt
->SetY(lpt
->m_originalPos
.y
);
1064 lpt
->m_point
->x
= lpt
->m_originalPos
.x
; lpt
->m_point
->y
= lpt
->m_originalPos
.y
;
1066 view
->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand(_T("Move line point"), (csDiagramDocument
*) view
->GetDocument(),
1067 new csCommandState(ID_CS_MOVE_LINE_POINT
, newShape
, this)));
1072 wxLabelShape
* csLineShape::OnCreateLabelShape(wxLineShape
*parent
, wxShapeRegion
*region
, double w
, double h
)
1074 return new csLabelShape(parent
, region
, w
, h
);
1078 bool csLineShape::OnLabelMovePre(wxDC
& dc
, wxLabelShape
* labelShape
, double x
, double y
, double old_x
, double old_y
, bool display
)
1080 csDiagramView
* view
= ((csCanvas
*)GetCanvas())->GetView();
1082 wxLineShape
* newShape
= (wxLineShape
*) this->CreateNewCopy();
1084 wxLineShape::OnLabelMovePre(dc
, labelShape
, x
, y
, old_x
, old_y
, display
);
1086 view
->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Move label", (csDiagramDocument
*) view
->GetDocument(),
1087 new csCommandState(ID_CS_MOVE_LABEL
, newShape
, this)));
1092 IMPLEMENT_DYNAMIC_CLASS(csLabelShape
, wxLabelShape
)
1094 csLabelShape::csLabelShape(wxLineShape
*parent
, wxShapeRegion
*region
, double w
, double h
):
1095 wxLabelShape(parent
, region
, w
, h
)
1099 // TODO: not sure how intercept normal behaviour (OnMovePre) to make
1100 // label movement undo-able.
1101 void csLabelShape::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
1103 wxLabelShape::OnEndDragLeft(x
, y
, keys
, attachment
);
1107 // Menu for editing shapes
1108 void studioShapeEditProc(wxMenu
& menu
, wxCommandEvent
& event
)
1110 wxShape
* shape
= (wxShape
*) menu
.GetClientData();
1111 csDiagramView
* view
= ((csCanvas
*)shape
->GetCanvas())->GetView();
1113 switch (event
.GetId())
1115 case ID_CS_EDIT_PROPERTIES
:
1117 csEvtHandler
* handler1
= (csEvtHandler
*)shape
->GetEventHandler();
1118 handler1
->EditProperties();
1120 csEvtHandler
* handler1
= (csEvtHandler
*)shape
->GetEventHandler();
1121 csLabelEditingDialog
* dialog
= new csLabelEditingDialog(shape
->GetCanvas()->GetParent());
1122 dialog
->SetShapeLabel(handler1
->m_label
);
1123 if (dialog
->ShowModal() == wxID_CANCEL
)
1129 wxString newLabel
= dialog
->GetShapeLabel();
1132 wxShape
* newShape
= shape
->CreateNewCopy();
1134 csEvtHandler
* handler2
= (csEvtHandler
*)newShape
->GetEventHandler();
1135 handler2
->m_label
= newLabel
;
1137 view
->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Edit label", (csDiagramDocument
*) view
->GetDocument(),
1138 new csCommandState(ID_CS_EDIT_LABEL
, newShape
, shape
)));
1149 case ID_CS_ROTATE_CLOCKWISE
:
1150 case ID_CS_ROTATE_ANTICLOCKWISE
:
1152 if (shape
->IsKindOf(CLASSINFO(wxLineShape
)))
1155 double theta
= shape
->GetRotation();
1156 const double myPi
= 3.1415926535897932384626433832795 ;
1157 double ninetyDegrees
= myPi
/2.0;
1160 if (event
.GetId() == ID_CS_ROTATE_CLOCKWISE
)
1162 theta
+= ninetyDegrees
;
1163 opStr
= _T("Rotate clockwise");
1167 theta
-= ninetyDegrees
;
1168 opStr
= _T("Rotate anticlockwise");
1171 if (theta
>= 2.0*myPi
|| theta
< 0.0)
1173 wxShape
* newShape
= shape
->CreateNewCopy();
1174 newShape
->Rotate(0.0, 0.0, theta
);
1177 newShapes
.Append(newShape
);
1178 oldShapes
.Append(shape
);
1179 view
->DoCmd(newShapes
, oldShapes
, event
.GetId(), opStr
);
1187 BEGIN_EVENT_TABLE(ShapeEditMenu
, wxMenu
)
1188 EVT_COMMAND_RANGE(1, 65000, wxEVT_COMMAND_MENU_SELECTED
, ShapeEditMenu::OnCommand
)
1191 void ShapeEditMenu::OnCommand(wxCommandEvent
& event
)
1193 studioShapeEditProc(*this, event
);