1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Implements Studio shapes
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
23 #if !wxUSE_DOC_VIEW_ARCHITECTURE
24 #error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in wx_setup.h!
27 #include <wx/ogl/ogl.h> // base header of OGL, includes and adjusts wx/deprecated/setup.h
33 #include "cspalette.h"
36 #define csSTANDARD_SHAPE_WIDTH 100
38 IMPLEMENT_CLASS(csDiagram
, wxDiagram
)
40 csDiagram::~csDiagram()
45 void csDiagram::Redraw(wxDC
& dc
)
47 wxDiagram::Redraw(dc
);
49 // Draw line crossings
50 wxLineCrossings lineCrossings
;
51 lineCrossings
.FindCrossings(*this);
52 lineCrossings
.DrawCrossings(*this, dc
);
56 * csEvtHandler: an event handler class for all shapes
59 IMPLEMENT_DYNAMIC_CLASS(csEvtHandler
, wxShapeEvtHandler
)
61 csEvtHandler::csEvtHandler(wxShapeEvtHandler
*prev
, wxShape
*shape
, const wxString
& lab
):
62 wxShapeEvtHandler(prev
, shape
)
67 csEvtHandler::~csEvtHandler()
71 // Copy any event handler data
72 void csEvtHandler::CopyData(wxShapeEvtHandler
& copy
)
74 wxShapeEvtHandler::CopyData(copy
);
76 csEvtHandler
& csCopy
= (csEvtHandler
&) copy
;
77 csCopy
.m_label
= m_label
;
80 void csEvtHandler::OnLeftClick(double WXUNUSED(x
), double WXUNUSED(y
), int keys
, int WXUNUSED(attachment
))
82 wxClientDC
dc(GetShape()->GetCanvas());
83 GetShape()->GetCanvas()->PrepareDC(dc
);
85 csDiagramView
* view
= ((csCanvas
*)GetShape()->GetCanvas())->GetView();
86 view
->ReflectPointSize(GetShape()->GetFont()->GetPointSize());
88 if (GetShape()->IsKindOf(CLASSINFO(wxLineShape
)))
89 view
->ReflectArrowState((wxLineShape
*) GetShape());
91 csEditorToolPalette
*palette
= wxGetApp().GetDiagramPalette();
92 if (palette
->GetSelection() == PALETTE_TEXT_TOOL
)
94 view
->ReflectPointSize(GetShape()->GetFont()->GetPointSize());
98 csLabelEditingDialog
* dialog
= new csLabelEditingDialog(GetShape()->GetCanvas()->GetParent());
99 dialog
->SetShapeLabel(m_label
);
100 if (dialog
->ShowModal() == wxID_CANCEL
)
106 wxString newLabel
= dialog
->GetShapeLabel();
109 wxShape
* newShape
= GetShape()->CreateNewCopy();
111 csEvtHandler
* handler
= (csEvtHandler
*)newShape
->GetEventHandler();
112 handler
->m_label
= newLabel
;
114 view
->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Edit label", (csDiagramDocument
*) view
->GetDocument(),
115 new csCommandState(ID_CS_EDIT_PROPERTIES
, newShape
, GetShape())));
122 // If no shift key, then everything is deselected.
123 // If the shape was selected, deselect it and vice versa.
124 bool selected
= GetShape()->Selected();
126 view
->SelectAll(false);
128 selected
= !selected
;
130 GetShape()->Select(selected
, &dc
);
131 GetShape()->GetCanvas()->Redraw(dc
); // Redraw because bits of objects will be missing
133 view
->SelectShape(GetShape(), selected
);
135 else if (keys
& KEY_SHIFT
)
137 if (GetShape()->Selected())
139 GetShape()->Select(false, &dc
);
140 view
->SelectShape(GetShape(), false);
144 GetShape()->Select(true, &dc
);
145 view
->SelectShape(GetShape(), true);
147 GetShape()->GetCanvas()->Redraw(dc
); // Redraw because bits of objects will be missing
149 else if (keys
& KEY_CTRL
)
151 // Do something for CONTROL
156 ((wxFrame
*)wxGetApp().GetTopWindow())->SetStatusText(m_label
);
157 #endif // wxUSE_STATUSBAR
161 void csEvtHandler::OnRightClick(double x
, double y
, int WXUNUSED(keys
), int WXUNUSED(attachment
))
163 // Have to convert back to physical coordinates from logical coordinates.
165 int viewStartX
, viewStartY
;
167 GetShape()->GetCanvas()->GetViewStart(& viewStartX
, & viewStartY
);
168 GetShape()->GetCanvas()->GetScrollPixelsPerUnit(& unitX
, & unitY
);
170 int x1
= (int)(x
* GetShape()->GetCanvas()->GetScaleX());
171 int y1
= (int)(y
* GetShape()->GetCanvas()->GetScaleY());
173 int menuX
= (int) (x1
- (viewStartX
* unitX
)) ;
174 int menuY
= (int) (y1
- (viewStartY
* unitY
));
176 wxGetApp().GetShapeEditMenu()->SetClientData((char*) GetShape());
177 wxGetApp().GetShapeEditMenu()->Enable(ID_CS_ROTATE_CLOCKWISE
, !GetShape()->IsKindOf(CLASSINFO(wxLineShape
)));
178 wxGetApp().GetShapeEditMenu()->Enable(ID_CS_ROTATE_ANTICLOCKWISE
, !GetShape()->IsKindOf(CLASSINFO(wxLineShape
)));
180 GetShape()->GetCanvas()->PopupMenu(wxGetApp().GetShapeEditMenu(), menuX
, menuY
);
184 * Implement connection of two shapes by right-dragging between them.
187 void csEvtHandler::OnBeginDragRight(double x
, double y
, int WXUNUSED(keys
), int attachment
)
189 wxClientDC
dc(GetShape()->GetCanvas());
190 GetShape()->GetCanvas()->PrepareDC(dc
);
192 wxPen
dottedPen(*wxBLACK
, 1, wxDOT
);
193 dc
.SetLogicalFunction(OGLRBLF
);
194 dc
.SetPen(dottedPen
);
196 GetShape()->GetAttachmentPositionEdge(attachment
, &xp
, &yp
);
197 dc
.DrawLine((wxCoord
)xp
, (wxCoord
)yp
, (wxCoord
)x
, (wxCoord
)y
);
198 GetShape()->GetCanvas()->CaptureMouse();
201 void csEvtHandler::OnDragRight(bool WXUNUSED(draw
), double x
, double y
, int WXUNUSED(keys
), int attachment
)
203 wxClientDC
dc(GetShape()->GetCanvas());
204 GetShape()->GetCanvas()->PrepareDC(dc
);
206 wxPen
dottedPen(*wxBLACK
, 1, wxDOT
);
207 dc
.SetLogicalFunction(OGLRBLF
);
208 dc
.SetPen(dottedPen
);
210 GetShape()->GetAttachmentPositionEdge(attachment
, &xp
, &yp
);
211 dc
.DrawLine((wxCoord
)xp
, (wxCoord
)yp
, (wxCoord
)x
, (wxCoord
)y
);
214 void csEvtHandler::OnEndDragRight(double x
, double y
, int WXUNUSED(keys
), int attachment
)
216 GetShape()->GetCanvas()->ReleaseMouse();
217 csCanvas
*canvas
= (csCanvas
*)GetShape()->GetCanvas();
219 // Check if we're on an object
221 wxShape
*otherShape
= canvas
->FindFirstSensitiveShape(x
, y
, &new_attachment
, OP_DRAG_RIGHT
);
223 if (otherShape
&& !otherShape
->IsKindOf(CLASSINFO(wxLineShape
)))
225 wxLineShape
* theShape
= new csLineShape
;
227 theShape
->AssignNewIds();
228 theShape
->SetEventHandler(new csEvtHandler(theShape
, theShape
, wxEmptyString
));
229 theShape
->SetPen(wxBLACK_PEN
);
230 theShape
->SetBrush(wxRED_BRUSH
);
232 wxToolBar
* toolbar
= wxGetApp().GetDiagramToolBar();
233 bool haveArrow
= toolbar
->GetToolState(DIAGRAM_TOOLBAR_LINE_ARROW
);
235 wxLineShape
*lineShape
= (wxLineShape
*)theShape
;
237 // Yes, you can have more than 2 control points, in which case
238 // it becomes a multi-segment line.
239 lineShape
->MakeLineControlPoints(2);
242 lineShape
->AddArrow(ARROW_ARROW
, ARROW_POSITION_MIDDLE
, 10.0, 0.0, _T("Normal arrowhead"));
244 lineShape
->SetFrom(GetShape());
245 lineShape
->SetTo(otherShape
);
246 lineShape
->SetAttachments(attachment
, new_attachment
);
248 canvas
->GetView()->GetDocument()->GetCommandProcessor()->Submit(
249 new csDiagramCommand(_T("Line"), (csDiagramDocument
*)canvas
->GetView()->GetDocument(),
250 new csCommandState(ID_CS_ADD_LINE
, lineShape
, NULL
)));
254 static double g_DragOffsetX
= 0.0;
255 static double g_DragOffsetY
= 0.0;
256 static double g_DragStartX
= 0.0;
257 static double g_DragStartY
= 0.0;
259 void csEvtHandler::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
261 if ((GetShape()->GetSensitivityFilter() & OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
265 if (GetShape()->GetParent())
267 GetShape()->GetParent()->HitTest(x
, y
, &attachment
, &dist
);
268 GetShape()->GetParent()->GetEventHandler()->OnDragLeft(draw
, x
, y
, keys
, attachment
);
273 wxClientDC
dc(GetShape()->GetCanvas());
274 GetShape()->GetCanvas()->PrepareDC(dc
);
276 dc
.SetLogicalFunction(OGLRBLF
);
278 wxPen
dottedPen(*wxBLACK
, 1, wxDOT
);
279 dc
.SetPen(dottedPen
);
280 dc
.SetBrush(* wxTRANSPARENT_BRUSH
);
283 xx
= x
+ g_DragOffsetX
;
284 yy
= y
+ g_DragOffsetY
;
286 GetShape()->GetCanvas()->Snap(&xx
, &yy
);
288 double offsetX
= xx
- g_DragStartX
;
289 double offsetY
= yy
- g_DragStartY
;
291 // m_xpos = xx; m_ypos = yy;
293 GetShape()->GetBoundingBoxMax(&w
, &h
);
294 GetShape()->GetEventHandler()->OnDrawOutline(dc
, xx
, yy
, w
, h
);
296 // Draw bounding box for other selected shapes
297 wxObjectList::compatibility_iterator node
= GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->GetFirst();
300 wxShape
* shape
= (wxShape
*) node
->GetData();
301 if (shape
->Selected() && !shape
->IsKindOf(CLASSINFO(wxLineShape
)) && (shape
!= GetShape()))
303 shape
->GetBoundingBoxMax(&w
, &h
);
304 shape
->OnDrawOutline(dc
, shape
->GetX() + offsetX
, shape
->GetY() + offsetY
, w
, h
);
306 node
= node
->GetNext();
310 void csEvtHandler::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
312 if ((GetShape()->GetSensitivityFilter() & OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
316 if (GetShape()->GetParent())
318 GetShape()->GetParent()->HitTest(x
, y
, &attachment
, &dist
);
319 GetShape()->GetParent()->GetEventHandler()->OnBeginDragLeft(x
, y
, keys
, attachment
);
324 wxClientDC
dc(GetShape()->GetCanvas());
325 GetShape()->GetCanvas()->PrepareDC(dc
);
327 // New policy: don't erase shape until end of drag.
330 g_DragOffsetX
= GetShape()->GetX() - x
;
331 g_DragOffsetY
= GetShape()->GetY() - y
;
334 xx
= x
+ g_DragOffsetX
;
335 yy
= y
+ g_DragOffsetY
;
337 GetShape()->GetCanvas()->Snap(&xx
, &yy
);
339 g_DragStartX
= GetShape()->GetX();
340 g_DragStartY
= GetShape()->GetY();
342 double offsetX
= xx
- g_DragStartX
;
343 double offsetY
= yy
- g_DragStartY
;
345 dc
.SetLogicalFunction(OGLRBLF
);
347 wxPen
dottedPen(*wxBLACK
, 1, wxDOT
);
348 dc
.SetPen(dottedPen
);
349 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
352 GetShape()->GetBoundingBoxMax(&w
, &h
);
353 GetShape()->GetEventHandler()->OnDrawOutline(dc
, xx
, yy
, w
, h
);
355 // Draw bounding box for other selected shapes
356 wxObjectList::compatibility_iterator node
= GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->GetFirst();
359 wxShape
* shape
= (wxShape
*) node
->GetData();
360 if (shape
->Selected() && !shape
->IsKindOf(CLASSINFO(wxLineShape
)) && (shape
!= GetShape()))
362 shape
->GetBoundingBoxMax(&w
, &h
);
363 shape
->OnDrawOutline(dc
, shape
->GetX() + offsetX
, shape
->GetY() + offsetY
, w
, h
);
365 node
= node
->GetNext();
368 GetShape()->GetCanvas()->CaptureMouse();
372 void csEvtHandler::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
374 csCanvas
*canvas
= (csCanvas
*)GetShape()->GetCanvas();
376 canvas
->ReleaseMouse();
377 if ((GetShape()->GetSensitivityFilter() & OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
381 if (GetShape()->GetParent())
383 GetShape()->GetParent()->HitTest(x
, y
, &attachment
, &dist
);
384 GetShape()->GetParent()->GetEventHandler()->OnEndDragLeft(x
, y
, keys
, attachment
);
389 wxClientDC
dc(canvas
);
390 canvas
->PrepareDC(dc
);
392 dc
.SetLogicalFunction(wxCOPY
);
394 double xx
= x
+ g_DragOffsetX
;
395 double yy
= y
+ g_DragOffsetY
;
397 canvas
->Snap(&xx
, &yy
);
399 double offsetX
= xx
- g_DragStartX
;
400 double offsetY
= yy
- g_DragStartY
;
402 wxShape
* newShape
= GetShape()->CreateNewCopy();
407 csDiagramCommand
* cmd
= new csDiagramCommand(_T("Move"), (csDiagramDocument
*)canvas
->GetView()->GetDocument(),
408 new csCommandState(ID_CS_MOVE
, newShape
, GetShape()));
411 wxObjectList::compatibility_iterator node
= GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->GetFirst();
414 wxShape
* shape
= (wxShape
*) node
->GetData();
415 // Only move the line point(s) if both ends move too
416 if (shape
->IsKindOf(CLASSINFO(wxLineShape
)) &&
417 ((wxLineShape
*)shape
)->GetTo()->Selected() && ((wxLineShape
*)shape
)->GetFrom()->Selected())
419 wxLineShape
* lineShape
= (wxLineShape
*) shape
;
421 if (lineShape
->GetLineControlPoints()->GetCount() > 2)
423 wxLineShape
* newLineShape
= (wxLineShape
*) lineShape
->CreateNewCopy();
425 wxObjectList::compatibility_iterator node1
= newLineShape
->GetLineControlPoints()->GetFirst();
428 wxRealPoint
*point
= (wxRealPoint
*)node1
->GetData();
431 node1
= node1
->GetNext();
433 cmd
->AddState(new csCommandState(ID_CS_MOVE_LINE_POINT
, newLineShape
, lineShape
));
434 lineShape
->Erase(dc
);
437 node
= node
->GetNext();
440 // Add other selected node shapes, if any
441 node
= GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->GetFirst();
444 wxShape
* shape
= (wxShape
*) node
->GetData();
445 if (shape
->Selected() && !shape
->IsKindOf(CLASSINFO(wxLineShape
)) && (shape
!= GetShape()))
447 wxShape
* newShape2
= shape
->CreateNewCopy();
448 newShape2
->SetX(shape
->GetX() + offsetX
);
449 newShape2
->SetY(shape
->GetY() + offsetY
);
450 cmd
->AddState(new csCommandState(ID_CS_MOVE
, newShape2
, shape
));
452 node
= node
->GetNext();
455 canvas
->GetView()->GetDocument()->GetCommandProcessor()->Submit(cmd
);
458 void csEvtHandler::OnSizingEndDragLeft(wxControlPoint
* pt
, double x
, double y
, int keys
, int attachment
)
460 wxShape
* shape
= GetShape();
461 csCanvas
*canvas
= (csCanvas
*)GetShape()->GetCanvas();
463 if (shape
->IsKindOf(CLASSINFO(wxLineShape
)))
465 // TODO: Do/Undo support for line operations
466 ((wxLineShape
*)shape
)->wxLineShape::OnSizingEndDragLeft(pt
, x
, y
, keys
, attachment
);
468 wxLineShape
* lineShape
= (wxLineShape
*) shape
;
470 wxLineControlPoint
* lpt
= (wxLineControlPoint
*) pt
;
472 wxClientDC
dc(canvas
);
473 canvas
->PrepareDC(dc
);
475 shape
->SetDisableLabel(false);
477 if (lpt
->m_type
== CONTROL_POINT_LINE
)
479 canvas
->Snap(&x
, &y
);
481 dc
.SetLogicalFunction(wxCOPY
);
482 lpt
->SetX(x
); lpt
->SetY(y
);
483 lpt
->m_point
->x
= x
; lpt
->m_point
->y
= y
;
485 this->OnMoveLink(dc
);
487 if (lpt
->m_type
== CONTROL_POINT_ENDPOINT_FROM
)
489 if (lpt
->m_oldCursor
)
490 canvas
->SetCursor(lpt
->m_oldCursor
);
491 lineShape
->Erase(dc
);
493 lpt
->SetX(x
); lpt
->SetY(y
);
495 if (lineShape
->GetFrom())
497 lineShape
->GetFrom()->MoveLineToNewAttachment(dc
, lineShape
, x
, y
);
500 if (lpt
->m_type
== CONTROL_POINT_ENDPOINT_TO
)
502 if (lpt
->m_oldCursor
)
503 canvas
->SetCursor(lpt
->m_oldCursor
);
505 lpt
->SetX(x
); lpt
->SetY(y
);
507 if (lineShape
->GetTo())
509 lineShape
->GetTo()->MoveLineToNewAttachment(dc
, lineShape
, x
, y
);
516 wxClientDC
dc(canvas
);
517 canvas
->PrepareDC(dc
);
519 canvas
->ReleaseMouse();
520 dc
.SetLogicalFunction(wxCOPY
);
525 shape->ResetControlPoints();
526 if (!pt->m_eraseObject)
530 wxShape
* newShape
= shape
->CreateNewCopy();
532 if (newShape
->IsKindOf(CLASSINFO(wxPolygonShape
)))
534 wxPolygonControlPoint
* ppt
= (wxPolygonControlPoint
*) pt
;
535 newShape
->SetSize(ppt
->GetNewSize().x
, ppt
->GetNewSize().y
);
537 ((wxPolygonShape
*)newShape
)->CalculateBoundingBox();
538 ((wxPolygonShape
*)newShape
)->CalculatePolygonCentre();
539 newShape
->ResetControlPoints();
543 newShape
->SetSize(pt
->sm_controlPointDragEndWidth
, pt
->sm_controlPointDragEndHeight
);
544 if (shape
->GetCentreResize())
546 // Old position is fine
550 newShape
->SetX(pt
->sm_controlPointDragPosX
);
551 newShape
->SetY(pt
->sm_controlPointDragPosY
);
555 csDiagramCommand
* cmd
= new csDiagramCommand(_T("Size"), (csDiagramDocument
*)canvas
->GetView()->GetDocument(),
556 new csCommandState(ID_CS_SIZE
, newShape
, shape
));
558 canvas
->GetView()->GetDocument()->GetCommandProcessor()->Submit(cmd
);
562 void csEvtHandler::OnEndSize(double WXUNUSED(x
), double WXUNUSED(y
))
564 wxClientDC
dc(GetShape()->GetCanvas());
565 GetShape()->GetCanvas()->PrepareDC(dc
);
567 GetShape()->FormatText(dc
, m_label
);
570 void csEvtHandler::OnChangeAttachment(int attachment
, wxLineShape
* line
, wxList
& ordering
)
572 csCanvas
*canvas
= (csCanvas
*)GetShape()->GetCanvas();
574 // We actually submit two different states: one to change the ordering, and another
575 // to change the attachment for the line.
576 // Problem. If we refresh after the attachment change, we'll get a flicker.
577 // We really want to do both in a oner.
579 csDiagramCommand
* cmd
= new csDiagramCommand(_T("Change attachment"), (csDiagramDocument
*)canvas
->GetView()->GetDocument());
581 wxLineShape
* newLine
= (wxLineShape
*) line
->CreateNewCopy();
582 if (line
->GetTo() == GetShape())
583 newLine
->SetAttachmentTo(attachment
);
585 newLine
->SetAttachmentFrom(attachment
);
587 cmd
->AddState(new csCommandState(ID_CS_CHANGE_LINE_ATTACHMENT
, newLine
, line
));
590 wxShape
* newShape
= GetShape()->CreateNewCopy();
591 newShape
->ApplyAttachmentOrdering(ordering
);
593 cmd
->AddState(new csCommandState(ID_CS_CHANGE_LINE_ORDERING
, newShape
, GetShape()));
595 canvas
->GetView()->GetDocument()->GetCommandProcessor()->Submit(cmd
);
598 void csEvtHandler::OnLeftDoubleClick(double WXUNUSED(x
), double WXUNUSED(y
), int WXUNUSED(keys
), int WXUNUSED(attachment
))
603 // Popup up a property dialog
604 bool csEvtHandler::EditProperties()
606 wxShape
* shape
= GetShape();
608 // For now, no line property editing
609 if (shape
->IsKindOf(CLASSINFO(wxLineShape
)))
612 csDiagramView
* view
= ((csCanvas
*)shape
->GetCanvas())->GetView();
614 wxPanel
* attributeDialog
;
615 wxString attributeDialogName
;
618 if (shape
->IsKindOf(CLASSINFO(csThinRectangleShape
)))
620 attributeDialog
= new csThinRectangleDialog
;
621 attributeDialogName
= _T("thin_rectangle");
622 title
= _T("Thin Rectangle Properties");
624 else if (shape
->IsKindOf(CLASSINFO(csWideRectangleShape
)))
626 attributeDialog
= new csWideRectangleDialog
;
627 attributeDialogName
= _T("wide_rectangle");
628 title
= _T("Wide Rectangle Properties");
630 else if (shape
->IsKindOf(CLASSINFO(csTriangleShape
)))
632 attributeDialog
= new csTriangleDialog
;
633 attributeDialogName
= _T("triangle");
634 title
= _T("Triangle Properties");
636 else if (shape
->IsKindOf(CLASSINFO(csSemiCircleShape
)))
638 attributeDialog
= new csSemiCircleDialog
;
639 attributeDialogName
= _T("semi_circle");
640 title
= _T("Semicircle Properties");
642 else if (shape
->IsKindOf(CLASSINFO(csCircleShape
)))
644 attributeDialog
= new csCircleDialog
;
645 attributeDialogName
= _T("circle");
646 title
= _T("Circle Properties");
648 else if (shape
->IsKindOf(CLASSINFO(csCircleShadowShape
)))
650 attributeDialog
= new csCircleShadowDialog
;
651 attributeDialogName
= _T("circle_shadow");
652 title
= _T("Circle Shadow Properties");
654 else if (shape
->IsKindOf(CLASSINFO(csTextBoxShape
)))
656 attributeDialog
= new csTextBoxDialog
;
657 attributeDialogName
= _T("text_box");
658 title
= _T("Text Box Properties");
660 else if (shape
->IsKindOf(CLASSINFO(csGroupShape
)))
662 attributeDialog
= new csGroupDialog
;
663 attributeDialogName
= _T("group");
664 title
= _T("Group Properties");
666 else if (shape
->IsKindOf(CLASSINFO(csOctagonShape
)))
668 attributeDialog
= new csOctagonDialog
;
669 attributeDialogName
= _T("octagon");
670 title
= _T("Octagon Properties");
674 wxMessageBox(_T("Unrecognised shape."), _T("Studio"), wxICON_EXCLAMATION
);
678 wxString
newLabel(m_label
);
680 #if wxUSE_WX_RESOURCES
681 csShapePropertiesDialog
* dialog
= new csShapePropertiesDialog(shape
->GetCanvas()->GetParent(), title
, attributeDialog
, attributeDialogName
);
682 dialog
->GetGeneralPropertiesDialog()->SetShapeLabel(m_label
);
683 if (dialog
->ShowModal() == wxID_CANCEL
)
689 newLabel
= dialog
->GetGeneralPropertiesDialog()->GetShapeLabel();
692 wxUnusedVar(attributeDialog
);
693 #endif // wxUSE_WX_RESOURCES
695 wxShape
* newShape
= shape
->CreateNewCopy();
697 csEvtHandler
* handler2
= (csEvtHandler
*)newShape
->GetEventHandler();
698 handler2
->m_label
= newLabel
;
700 view
->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand(_T("Edit properties"), (csDiagramDocument
*) view
->GetDocument(),
701 new csCommandState(ID_CS_EDIT_PROPERTIES
, newShape
, shape
)));
711 bool csDiagram::OnShapeSave(wxExprDatabase
& db
, wxShape
& shape
, wxExpr
& expr
)
713 wxDiagram::OnShapeSave(db
, shape
, expr
);
714 csEvtHandler
*handler
= (csEvtHandler
*)shape
.GetEventHandler();
715 expr
.AddAttributeValueString(_T("label"), handler
->m_label
);
719 bool csDiagram::OnShapeLoad(wxExprDatabase
& db
, wxShape
& shape
, wxExpr
& expr
)
721 wxDiagram::OnShapeLoad(db
, shape
, expr
);
722 wxString label
= wxEmptyString
;
723 expr
.GetAttributeValue(_T("label"), label
);
724 csEvtHandler
*handler
= new csEvtHandler(&shape
, &shape
, label
);
725 shape
.SetEventHandler(handler
);
729 #endif // wxUSE_PROLOGIO
731 IMPLEMENT_DYNAMIC_CLASS(csThinRectangleShape
, wxDrawnShape
)
733 csThinRectangleShape::csThinRectangleShape()
735 SetDrawnPen(wxBLACK_PEN
);
736 wxBrush
* brush
= wxTheBrushList
->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID
);
737 SetDrawnBrush(brush
);
739 double w
= csSTANDARD_SHAPE_WIDTH
/2;
740 double h
= csSTANDARD_SHAPE_WIDTH
;
742 DrawRectangle(wxRect((int)(- w
/2), (int)(- h
/2), (int)(w
), (int)(h
)));
745 SetAttachmentMode(ATTACHMENT_MODE_BRANCHING
);
746 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
747 SetCentreResize(false);
750 IMPLEMENT_DYNAMIC_CLASS(csWideRectangleShape
, wxDrawnShape
)
752 csWideRectangleShape::csWideRectangleShape()
754 SetDrawnPen(wxBLACK_PEN
);
755 wxBrush
* brush
= wxTheBrushList
->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID
);
756 SetDrawnBrush(brush
);
758 double w
= csSTANDARD_SHAPE_WIDTH
;
761 DrawRoundedRectangle(wxRect((int)(- w
/2), (int)(- h
/2), (int)(w
), (int)(h
)), -0.3);
764 SetAttachmentMode(ATTACHMENT_MODE_BRANCHING
);
765 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
766 SetCentreResize(false);
769 IMPLEMENT_DYNAMIC_CLASS(csTriangleShape
, wxDrawnShape
)
771 csTriangleShape::csTriangleShape()
773 SetDrawnPen(wxBLACK_PEN
);
774 wxBrush
* brush
= wxTheBrushList
->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID
);
775 SetDrawnBrush(brush
);
777 double w
= csSTANDARD_SHAPE_WIDTH
;
778 double h
= (csSTANDARD_SHAPE_WIDTH
*2.0)/3.0;
780 // Triangle, from top vertex
781 wxPoint
* points
= new wxPoint
[3];
784 points
[0] = wxPoint( 0 , (int)(- h
/ 2) );
785 points
[1] = wxPoint( (int)(w
/ 2) , (int)(h
/ 2) );
786 points
[2] = wxPoint( (int)(-w
/ 2), (int)(h
/ 2) );
788 DrawPolygon(3, points
, oglMETAFLAGS_OUTLINE
);
792 // Add another triangle at the top for the black bit
793 SetDrawnBrush(wxBLACK_BRUSH
);
795 points
= new wxPoint
[3];
797 // Calculate where the new points will be, using the proportions
799 double h1
= 8; // Height of little triangle.
802 Formula: ((w/2) / h) = w1 / h1
803 w1 = ((w/2) / h) * h1;
805 double ratio
= ((w
/2.0) / h
) ;
806 double w1
= ratio
* h1
;
808 points
[0] = wxPoint(0 , (int) (- h
/ 2 ));
809 points
[1] = wxPoint( (int) w1
, (int) (- h
/ 2 + h1
));
810 points
[2] = wxPoint( (int) -w1
, (int) (- h
/ 2 + h1
));
812 DrawPolygon(3, points
);
818 SetAttachmentMode(ATTACHMENT_MODE_BRANCHING
);
819 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
820 SetCentreResize(false);
823 IMPLEMENT_DYNAMIC_CLASS(csSemiCircleShape
, wxDrawnShape
)
825 csSemiCircleShape::csSemiCircleShape()
828 DrawAtAngle(oglDRAWN_ANGLE_0
);
830 double w
= csSTANDARD_SHAPE_WIDTH
;
833 SetDrawnPen(wxTRANSPARENT_PEN
);
834 SetDrawnBrush(wxTRANSPARENT_BRUSH
);
836 // Draw a dummy rectangle that will be used for calculating the
837 // bounding box, since we can't calculate the bounding box for
838 // an arbitrary arc (not implemented)
840 DrawRectangle(wxRect((int)(-w
/2.0), (int)(-h
/2.0), (int)(w
), (int)(h
)));
842 SetDrawnPen(wxBLACK_PEN
);
843 wxBrush
* brush
= wxTheBrushList
->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID
);
844 SetDrawnBrush(brush
);
846 DrawEllipticArc(wxRect((int)(-w
/2), (int)(-h
/2), (int)(w
), (int)(2*h
)), 0.0, 180.0);
847 DrawLine(wxPoint((int)(-w
/2), (int)(h
/2)), wxPoint((int)(w
/2), (int)(h
/2)));
853 w
= csSTANDARD_SHAPE_WIDTH
/2;
854 h
= csSTANDARD_SHAPE_WIDTH
;
856 DrawAtAngle(oglDRAWN_ANGLE_90
);
858 SetDrawnPen(wxTRANSPARENT_PEN
);
859 SetDrawnBrush(wxTRANSPARENT_BRUSH
);
861 DrawRectangle(wxRect((int)(-w
/2), (int)(-h
/2), (int)(w
), (int)(h
)));
863 SetDrawnPen(wxBLACK_PEN
);
864 SetDrawnBrush(brush
);
866 DrawEllipticArc(wxRect((int)(-w
/2 - w
), (int)(-h
/2), (int)(2*w
), (int)(h
)), 270.0, 90.0);
867 DrawLine(wxPoint((int)(-w
/2), (int)(-h
/2)), wxPoint((int)(-w
/2), (int)(h
/2)));
873 DrawAtAngle(oglDRAWN_ANGLE_180
);
875 w
= csSTANDARD_SHAPE_WIDTH
;
876 h
= csSTANDARD_SHAPE_WIDTH
/2;
878 SetDrawnPen(wxTRANSPARENT_PEN
);
879 SetDrawnBrush(wxTRANSPARENT_BRUSH
);
881 DrawRectangle(wxRect((int)(-w
/2), (int)(-h
/2), (int)(w
), (int)(h
)));
883 SetDrawnPen(wxBLACK_PEN
);
884 SetDrawnBrush(brush
);
886 DrawEllipticArc(wxRect((int)(-w
/2), (int)(-h
/2 - h
), (int)(w
), (int)(2*h
)), 180.0, 0.0);
887 DrawLine(wxPoint((int)(-w
/2), (int)(-h
/2)), wxPoint((int)(w
/2), (int)(-h
/2)));
893 DrawAtAngle(oglDRAWN_ANGLE_270
);
895 w
= csSTANDARD_SHAPE_WIDTH
/2;
896 h
= csSTANDARD_SHAPE_WIDTH
;
898 SetDrawnPen(wxTRANSPARENT_PEN
);
899 SetDrawnBrush(wxTRANSPARENT_BRUSH
);
901 DrawRectangle(wxRect((int)(-w
/2), (int)(-h
/2), (int)(w
), (int)(h
)));
903 SetDrawnPen(wxBLACK_PEN
);
904 SetDrawnBrush(brush
);
906 DrawEllipticArc(wxRect((int)(-w
/2), (int)(-h
/2), (int)(2*w
), (int)(h
)), 90.0, 270.0);
907 DrawLine(wxPoint((int)(w
/2),(int)(-h
/2)), wxPoint((int)(w
/2), (int)(h
/2)));
912 DrawAtAngle(oglDRAWN_ANGLE_0
);
915 SetAttachmentMode(ATTACHMENT_MODE_BRANCHING
);
916 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
917 SetCentreResize(false);
920 IMPLEMENT_DYNAMIC_CLASS(csCircleShape
, wxCircleShape
)
922 csCircleShape::csCircleShape()
925 wxBrush
* brush
= wxTheBrushList
->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID
);
928 SetSize(csSTANDARD_SHAPE_WIDTH
*0.6, csSTANDARD_SHAPE_WIDTH
*0.6);
930 SetAttachmentMode(ATTACHMENT_MODE_BRANCHING
);
931 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
932 SetCentreResize(false);
935 IMPLEMENT_DYNAMIC_CLASS(csCircleShadowShape
, wxCircleShape
)
937 csCircleShadowShape::csCircleShadowShape()
940 wxBrush
* brush
= wxTheBrushList
->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID
);
943 SetSize(csSTANDARD_SHAPE_WIDTH
*0.6, csSTANDARD_SHAPE_WIDTH
*0.6);
945 SetAttachmentMode(ATTACHMENT_MODE_BRANCHING
);
946 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
947 SetCentreResize(false);
948 SetShadowMode(SHADOW_RIGHT
);
951 IMPLEMENT_DYNAMIC_CLASS(csOctagonShape
, wxPolygonShape
)
953 csOctagonShape::csOctagonShape()
956 SetBrush(wxTheBrushList
->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID
));
958 double w
= csSTANDARD_SHAPE_WIDTH
*0.5;
959 double h
= csSTANDARD_SHAPE_WIDTH
*0.5;
963 wxList
* points
= new wxList
;
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
));
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
));
975 SetAttachmentMode(ATTACHMENT_MODE_BRANCHING
);
976 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
977 SetCentreResize(false);
980 // This is a transparent shape for drawing around other shapes.
981 IMPLEMENT_DYNAMIC_CLASS(csGroupShape
, wxRectangleShape
)
983 csGroupShape::csGroupShape()
985 SetPen(wxThePenList
->FindOrCreatePen(_T("BLACK"), 1, wxDOT
));
986 SetBrush(wxTRANSPARENT_BRUSH
);
988 SetSize(csSTANDARD_SHAPE_WIDTH
, csSTANDARD_SHAPE_WIDTH
);
989 SetCentreResize(false);
992 void csGroupShape::OnDraw(wxDC
& dc
)
994 wxRectangleShape::OnDraw(dc
);
997 // Must modify the hit-test so it doesn't obscure shapes that are inside.
998 bool csGroupShape::HitTest(double x
, double y
, int* attachment
, double* distance
)
1003 double width
= 0.0, height
= 0.0;
1004 GetBoundingBoxMin(&width
, &height
);
1006 double x1
= GetX() - (width
/2.0);
1007 double y1
= GetY() - (height
/2.0);
1008 double x2
= GetX() + (width
/2.0);
1009 double y2
= GetY() + (height
/2.0);
1011 double edgeTolerance
= 4.0;
1013 // Test each edge in turn
1016 if (x
>= x1
&& x
<= x2
)
1018 if ((y
>= y1
- edgeTolerance
) && (y
<= y1
+ edgeTolerance
))
1020 if ((y
<= y2
+ edgeTolerance
) && (y
>= y2
- edgeTolerance
))
1024 if (y
>= y1
&& y
<= y2
)
1026 if ((x
>= x1
- edgeTolerance
) && (x
<= x1
+ edgeTolerance
))
1028 if ((x
<= x2
+ edgeTolerance
) && (x
>= x2
- edgeTolerance
))
1035 IMPLEMENT_DYNAMIC_CLASS(csTextBoxShape
, wxRectangleShape
)
1037 csTextBoxShape::csTextBoxShape()
1039 SetPen(wxTRANSPARENT_PEN
);
1040 SetBrush(wxTRANSPARENT_BRUSH
);
1042 SetSize(csSTANDARD_SHAPE_WIDTH
, csSTANDARD_SHAPE_WIDTH
/2.0);
1044 SetAttachmentMode(ATTACHMENT_MODE_NONE
);
1045 SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL
|BRANCHING_ATTACHMENT_BLOB
);
1046 SetCentreResize(false);
1049 IMPLEMENT_DYNAMIC_CLASS(csLineShape
, wxLineShape
)
1051 csLineShape::csLineShape()
1055 bool csLineShape::OnMoveMiddleControlPoint(wxDC
& WXUNUSED(dc
), wxLineControlPoint
* lpt
, const wxRealPoint
& pt
)
1057 csDiagramView
* view
= ((csCanvas
*)GetCanvas())->GetView();
1059 // Temporarily set the new shape properties so we can copy it
1060 lpt
->SetX(pt
.x
); lpt
->SetY(pt
.y
);
1061 lpt
->m_point
->x
= pt
.x
; lpt
->m_point
->y
= pt
.y
;
1063 wxLineShape
* newShape
= (wxLineShape
*) this->CreateNewCopy();
1065 // Now set them back again
1066 lpt
->SetX(lpt
->m_originalPos
.x
); lpt
->SetY(lpt
->m_originalPos
.y
);
1067 lpt
->m_point
->x
= lpt
->m_originalPos
.x
; lpt
->m_point
->y
= lpt
->m_originalPos
.y
;
1069 view
->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand(_T("Move line point"), (csDiagramDocument
*) view
->GetDocument(),
1070 new csCommandState(ID_CS_MOVE_LINE_POINT
, newShape
, this)));
1075 wxLabelShape
* csLineShape::OnCreateLabelShape(wxLineShape
*parent
, wxShapeRegion
*region
, double w
, double h
)
1077 return new csLabelShape(parent
, region
, w
, h
);
1081 bool csLineShape::OnLabelMovePre(wxDC
& dc
, wxLabelShape
* labelShape
, double x
, double y
, double old_x
, double old_y
, bool display
)
1083 csDiagramView
* view
= ((csCanvas
*)GetCanvas())->GetView();
1085 wxLineShape
* newShape
= (wxLineShape
*) this->CreateNewCopy();
1087 wxLineShape::OnLabelMovePre(dc
, labelShape
, x
, y
, old_x
, old_y
, display
);
1089 view
->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Move label", (csDiagramDocument
*) view
->GetDocument(),
1090 new csCommandState(ID_CS_MOVE_LABEL
, newShape
, this)));
1095 IMPLEMENT_DYNAMIC_CLASS(csLabelShape
, wxLabelShape
)
1097 csLabelShape::csLabelShape(wxLineShape
*parent
, wxShapeRegion
*region
, double w
, double h
):
1098 wxLabelShape(parent
, region
, w
, h
)
1102 // TODO: not sure how intercept normal behaviour (OnMovePre) to make
1103 // label movement undo-able.
1104 void csLabelShape::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
1106 wxLabelShape::OnEndDragLeft(x
, y
, keys
, attachment
);
1110 // Menu for editing shapes
1111 void studioShapeEditProc(wxMenu
& menu
, wxCommandEvent
& event
)
1113 wxShape
* shape
= (wxShape
*) menu
.GetClientData();
1114 csDiagramView
* view
= ((csCanvas
*)shape
->GetCanvas())->GetView();
1116 switch (event
.GetId())
1118 case ID_CS_EDIT_PROPERTIES
:
1120 csEvtHandler
* handler1
= (csEvtHandler
*)shape
->GetEventHandler();
1121 handler1
->EditProperties();
1123 csEvtHandler
* handler1
= (csEvtHandler
*)shape
->GetEventHandler();
1124 csLabelEditingDialog
* dialog
= new csLabelEditingDialog(shape
->GetCanvas()->GetParent());
1125 dialog
->SetShapeLabel(handler1
->m_label
);
1126 if (dialog
->ShowModal() == wxID_CANCEL
)
1132 wxString newLabel
= dialog
->GetShapeLabel();
1135 wxShape
* newShape
= shape
->CreateNewCopy();
1137 csEvtHandler
* handler2
= (csEvtHandler
*)newShape
->GetEventHandler();
1138 handler2
->m_label
= newLabel
;
1140 view
->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Edit label", (csDiagramDocument
*) view
->GetDocument(),
1141 new csCommandState(ID_CS_EDIT_LABEL
, newShape
, shape
)));
1152 case ID_CS_ROTATE_CLOCKWISE
:
1153 case ID_CS_ROTATE_ANTICLOCKWISE
:
1155 if (shape
->IsKindOf(CLASSINFO(wxLineShape
)))
1158 double theta
= shape
->GetRotation();
1159 const double myPi
= M_PI
;
1160 double ninetyDegrees
= myPi
/2.0;
1163 if (event
.GetId() == ID_CS_ROTATE_CLOCKWISE
)
1165 theta
+= ninetyDegrees
;
1166 opStr
= _T("Rotate clockwise");
1170 theta
-= ninetyDegrees
;
1171 opStr
= _T("Rotate anticlockwise");
1174 if (theta
>= 2.0*myPi
|| theta
< 0.0)
1176 wxShape
* newShape
= shape
->CreateNewCopy();
1177 newShape
->Rotate(0.0, 0.0, theta
);
1180 newShapes
.Append(newShape
);
1181 oldShapes
.Append(shape
);
1182 view
->DoCmd(newShapes
, oldShapes
, event
.GetId(), opStr
);
1190 BEGIN_EVENT_TABLE(ShapeEditMenu
, wxMenu
)
1191 EVT_COMMAND_RANGE(1, 65000, wxEVT_COMMAND_MENU_SELECTED
, ShapeEditMenu::OnCommand
)
1194 void ShapeEditMenu::OnCommand(wxCommandEvent
& event
)
1196 studioShapeEditProc(*this, event
);