1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Implements document functionality in OGLEdit
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 #include <wx/ioswrap.h>
29 #if !wxUSE_DOC_VIEW_ARCHITECTURE
30 #error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in wx_setup.h!
37 IMPLEMENT_DYNAMIC_CLASS(DiagramDocument
, wxDocument
)
39 DiagramDocument::DiagramDocument(void)
43 DiagramDocument::~DiagramDocument(void)
47 bool DiagramDocument::OnCloseDocument(void)
49 diagram
.DeleteAllShapes();
53 #if wxUSE_STD_IOSTREAM
54 wxSTD ostream
& DiagramDocument::SaveObject(wxSTD ostream
& stream
)
58 wxDocument::SaveObject(stream
);
61 (void) wxGetTempFileName("diag", buf
);
63 diagram
.SaveFile(buf
);
64 wxTransferFileToStream(buf
, stream
);
73 wxSTD istream
& DiagramDocument::LoadObject(wxSTD istream
& stream
)
77 wxDocument::LoadObject(stream
);
80 (void) wxGetTempFileName("diag", buf
);
82 wxTransferStreamToFile(stream
, buf
);
84 diagram
.DeleteAllShapes();
85 diagram
.LoadFile(buf
);
94 wxOutputStream
& DiagramDocument::SaveObject(wxOutputStream
& stream
)
98 wxDocument::SaveObject(stream
);
100 (void) wxGetTempFileName(_T("diag"), buf
);
102 diagram
.SaveFile(buf
);
104 wxTransferFileToStream(buf
, stream
);
113 wxInputStream
& DiagramDocument::LoadObject(wxInputStream
& stream
)
116 wxDocument::LoadObject(stream
);
119 (void) wxGetTempFileName(_T("diag"), buf
);
121 wxTransferStreamToFile(stream
, buf
);
123 diagram
.DeleteAllShapes();
124 diagram
.LoadFile(buf
);
134 * Implementation of drawing command
137 DiagramCommand::DiagramCommand(const wxString
& name
, int command
, DiagramDocument
*ddoc
, wxClassInfo
*info
, double xx
, double yy
,
138 bool sel
, wxShape
*theShape
, wxShape
*fs
, wxShape
*ts
)
139 :wxCommand(true, name
)
155 DiagramCommand::DiagramCommand(const wxString
& name
, int command
, DiagramDocument
*ddoc
, wxBrush
*backgroundColour
, wxShape
*theShape
)
156 :wxCommand(true, name
)
168 shapeBrush
= backgroundColour
;
172 DiagramCommand::DiagramCommand(const wxString
& name
, int command
, DiagramDocument
*ddoc
, const wxString
& lab
, wxShape
*theShape
)
173 :wxCommand(true, name
)
190 DiagramCommand::~DiagramCommand(void)
192 if (shape
&& deleteShape
)
194 shape
->SetCanvas(NULL
);
199 bool DiagramCommand::Do(void)
209 shape
->Select(false);
211 // Generate commands to explicitly remove each connected line.
214 doc
->GetDiagram()->RemoveShape(shape
);
215 if (shape
->IsKindOf(CLASSINFO(wxLineShape
)))
217 wxLineShape
*lineShape
= (wxLineShape
*)shape
;
218 fromShape
= lineShape
->GetFrom();
219 toShape
= lineShape
->GetTo();
224 doc
->UpdateAllViews();
229 case OGLEDIT_ADD_SHAPE
:
233 theShape
= shape
; // Saved from undoing the shape
236 theShape
= (wxShape
*)shapeInfo
->CreateObject();
237 theShape
->AssignNewIds();
238 theShape
->SetEventHandler(new MyEvtHandler(theShape
, theShape
, wxEmptyString
));
239 theShape
->SetCentreResize(false);
240 theShape
->SetPen(wxBLACK_PEN
);
241 theShape
->SetBrush(wxCYAN_BRUSH
);
243 theShape
->SetSize(60, 60);
245 doc
->GetDiagram()->AddShape(theShape
);
246 theShape
->Show(true);
248 wxClientDC
dc(theShape
->GetCanvas());
249 theShape
->GetCanvas()->PrepareDC(dc
);
251 theShape
->Move(dc
, x
, y
);
257 doc
->UpdateAllViews();
260 case OGLEDIT_ADD_LINE
:
264 theShape
= shape
; // Saved from undoing the line
267 theShape
= (wxShape
*)shapeInfo
->CreateObject();
268 theShape
->AssignNewIds();
269 theShape
->SetEventHandler(new MyEvtHandler(theShape
, theShape
, wxEmptyString
));
270 theShape
->SetPen(wxBLACK_PEN
);
271 theShape
->SetBrush(wxRED_BRUSH
);
273 wxLineShape
*lineShape
= (wxLineShape
*)theShape
;
275 // Yes, you can have more than 2 control points, in which case
276 // it becomes a multi-segment line.
277 lineShape
->MakeLineControlPoints(2);
278 lineShape
->AddArrow(ARROW_ARROW
, ARROW_POSITION_END
, 10.0, 0.0, _T("Normal arrowhead"));
281 doc
->GetDiagram()->AddShape(theShape
);
283 fromShape
->AddLine((wxLineShape
*)theShape
, toShape
);
285 theShape
->Show(true);
287 wxClientDC
dc(theShape
->GetCanvas());
288 theShape
->GetCanvas()->PrepareDC(dc
);
290 // It won't get drawn properly unless you move both
292 fromShape
->Move(dc
, fromShape
->GetX(), fromShape
->GetY());
293 toShape
->Move(dc
, toShape
->GetX(), toShape
->GetY());
299 doc
->UpdateAllViews();
302 case OGLEDIT_CHANGE_BACKGROUND_COLOUR
:
306 wxClientDC
dc(shape
->GetCanvas());
307 shape
->GetCanvas()->PrepareDC(dc
);
309 wxBrush
*oldBrush
= shape
->GetBrush();
310 shape
->SetBrush(shapeBrush
);
311 shapeBrush
= oldBrush
;
315 doc
->UpdateAllViews();
320 case OGLEDIT_EDIT_LABEL
:
324 MyEvtHandler
*myHandler
= (MyEvtHandler
*)shape
->GetEventHandler();
325 wxString
oldLabel(myHandler
->label
);
326 myHandler
->label
= shapeLabel
;
327 shapeLabel
= oldLabel
;
329 wxClientDC
dc(shape
->GetCanvas());
330 shape
->GetCanvas()->PrepareDC(dc
);
332 shape
->FormatText(dc
, /* (char*) (const char*) */ myHandler
->label
);
336 doc
->UpdateAllViews();
345 bool DiagramCommand::Undo(void)
353 doc
->GetDiagram()->AddShape(shape
);
356 if (shape
->IsKindOf(CLASSINFO(wxLineShape
)))
358 wxLineShape
*lineShape
= (wxLineShape
*)shape
;
360 fromShape
->AddLine(lineShape
, toShape
);
368 doc
->UpdateAllViews();
371 case OGLEDIT_ADD_SHAPE
:
372 case OGLEDIT_ADD_LINE
:
376 wxClientDC
dc(shape
->GetCanvas());
377 shape
->GetCanvas()->PrepareDC(dc
);
379 shape
->Select(false, &dc
);
380 doc
->GetDiagram()->RemoveShape(shape
);
385 doc
->UpdateAllViews();
388 case OGLEDIT_CHANGE_BACKGROUND_COLOUR
:
392 wxClientDC
dc(shape
->GetCanvas());
393 shape
->GetCanvas()->PrepareDC(dc
);
395 wxBrush
*oldBrush
= shape
->GetBrush();
396 shape
->SetBrush(shapeBrush
);
397 shapeBrush
= oldBrush
;
401 doc
->UpdateAllViews();
405 case OGLEDIT_EDIT_LABEL
:
409 MyEvtHandler
*myHandler
= (MyEvtHandler
*)shape
->GetEventHandler();
410 wxString
oldLabel(myHandler
->label
);
411 myHandler
->label
= shapeLabel
;
412 shapeLabel
= oldLabel
;
414 wxClientDC
dc(shape
->GetCanvas());
415 shape
->GetCanvas()->PrepareDC(dc
);
417 shape
->FormatText(dc
, /* (char*) (const char*) */ myHandler
->label
);
421 doc
->UpdateAllViews();
430 // Remove each individual line connected to a shape by sending a command.
431 void DiagramCommand::RemoveLines(wxShape
*shape
)
433 wxObjectList::compatibility_iterator node
= shape
->GetLines().GetFirst();
436 wxLineShape
*line
= (wxLineShape
*)node
->GetData();
437 doc
->GetCommandProcessor()->Submit(new DiagramCommand(_T("Cut"), wxID_CUT
, doc
, NULL
, 0.0, 0.0, line
->Selected(), line
));
439 node
= shape
->GetLines().GetFirst();
444 * MyEvtHandler: an event handler class for all shapes
447 void MyEvtHandler::OnLeftClick(double WXUNUSED(x
), double WXUNUSED(y
), int keys
, int WXUNUSED(attachment
))
449 wxClientDC
dc(GetShape()->GetCanvas());
450 GetShape()->GetCanvas()->PrepareDC(dc
);
454 // Selection is a concept the library knows about
455 if (GetShape()->Selected())
457 GetShape()->Select(false, &dc
);
458 GetShape()->GetCanvas()->Redraw(dc
); // Redraw because bits of objects will be are missing
462 // Ensure no other shape is selected, to simplify Undo/Redo code
464 wxObjectList::compatibility_iterator node
= GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->GetFirst();
467 wxShape
*eachShape
= (wxShape
*)node
->GetData();
468 if (eachShape
->GetParent() == NULL
)
470 if (eachShape
->Selected())
472 eachShape
->Select(false, &dc
);
476 node
= node
->GetNext();
478 GetShape()->Select(true, &dc
);
480 GetShape()->GetCanvas()->Redraw(dc
);
483 else if (keys
& KEY_CTRL
)
485 // Do something for CONTROL
490 wxGetApp().frame
->SetStatusText(label
);
491 #endif // wxUSE_STATUSBAR
496 * Implement connection of two shapes by right-dragging between them.
499 void MyEvtHandler::OnBeginDragRight(double x
, double y
, int WXUNUSED(keys
), int attachment
)
501 // Force attachment to be zero for now. Eventually we can deal with
502 // the actual attachment point, e.g. a rectangle side if attachment mode is on.
505 wxClientDC
dc(GetShape()->GetCanvas());
506 GetShape()->GetCanvas()->PrepareDC(dc
);
508 wxPen
dottedPen(*wxBLACK
, 1, wxDOT
);
509 dc
.SetLogicalFunction(OGLRBLF
);
510 dc
.SetPen(dottedPen
);
512 GetShape()->GetAttachmentPosition(attachment
, &xp
, &yp
);
513 dc
.DrawLine((long) xp
, (long) yp
, (long) x
, (long) y
);
514 GetShape()->GetCanvas()->CaptureMouse();
517 void MyEvtHandler::OnDragRight(bool WXUNUSED(draw
), double x
, double y
, int WXUNUSED(keys
), int attachment
)
519 // Force attachment to be zero for now
522 wxClientDC
dc(GetShape()->GetCanvas());
523 GetShape()->GetCanvas()->PrepareDC(dc
);
525 wxPen
dottedPen(*wxBLACK
, 1, wxDOT
);
526 dc
.SetLogicalFunction(OGLRBLF
);
527 dc
.SetPen(dottedPen
);
529 GetShape()->GetAttachmentPosition(attachment
, &xp
, &yp
);
530 dc
.DrawLine((long) xp
, (long) yp
, (long) x
, (long) y
);
533 void MyEvtHandler::OnEndDragRight(double x
, double y
, int WXUNUSED(keys
), int WXUNUSED(attachment
))
535 GetShape()->GetCanvas()->ReleaseMouse();
536 MyCanvas
*canvas
= (MyCanvas
*)GetShape()->GetCanvas();
538 // Check if we're on an object
540 wxShape
*otherShape
= canvas
->FindFirstSensitiveShape(x
, y
, &new_attachment
, OP_DRAG_RIGHT
);
542 if (otherShape
&& !otherShape
->IsKindOf(CLASSINFO(wxLineShape
)))
544 canvas
->view
->GetDocument()->GetCommandProcessor()->Submit(
545 new DiagramCommand(_T("wxLineShape"), OGLEDIT_ADD_LINE
, (DiagramDocument
*)canvas
->view
->GetDocument(), CLASSINFO(wxLineShape
),
546 0.0, 0.0, false, NULL
, GetShape(), otherShape
));
550 void MyEvtHandler::OnEndSize(double WXUNUSED(x
), double WXUNUSED(y
))
552 wxClientDC
dc(GetShape()->GetCanvas());
553 GetShape()->GetCanvas()->PrepareDC(dc
);
555 GetShape()->FormatText(dc
, /* (char*) (const char*) */ label
);
564 bool MyDiagram::OnShapeSave(wxExprDatabase
& db
, wxShape
& shape
, wxExpr
& expr
)
566 wxDiagram::OnShapeSave(db
, shape
, expr
);
567 MyEvtHandler
*handler
= (MyEvtHandler
*)shape
.GetEventHandler();
568 expr
.AddAttributeValueString(_T("label"), handler
->label
);
572 bool MyDiagram::OnShapeLoad(wxExprDatabase
& db
, wxShape
& shape
, wxExpr
& expr
)
574 wxDiagram::OnShapeLoad(db
, shape
, expr
);
575 wxChar
*label
= NULL
;
576 expr
.AssignAttributeValue(_T("label"), &label
);
577 MyEvtHandler
*handler
= new MyEvtHandler(&shape
, &shape
, wxString(label
));
578 shape
.SetEventHandler(handler
);
591 IMPLEMENT_DYNAMIC_CLASS(wxRoundedRectangleShape
, wxRectangleShape
)
593 wxRoundedRectangleShape::wxRoundedRectangleShape(double w
, double h
):
594 wxRectangleShape(w
, h
)
596 // 0.3 of the smaller rectangle dimension
597 SetCornerRadius((double) -0.3);
600 IMPLEMENT_DYNAMIC_CLASS(wxDiamondShape
, wxPolygonShape
)
602 wxDiamondShape::wxDiamondShape(double w
, double h
):
605 // wxPolygonShape::SetSize relies on the shape having non-zero
612 wxList
*thePoints
= new wxList
;
613 wxRealPoint
*point
= new wxRealPoint(0.0, (-h
/2.0));
614 thePoints
->Append((wxObject
*) point
);
616 point
= new wxRealPoint((w
/2.0), 0.0);
617 thePoints
->Append((wxObject
*) point
);
619 point
= new wxRealPoint(0.0, (h
/2.0));
620 thePoints
->Append((wxObject
*) point
);
622 point
= new wxRealPoint((-w
/2.0), 0.0);
623 thePoints
->Append((wxObject
*) point
);