1 /////////////////////////////////////////////////////////////////////////////
2 // Name: contrib/samples/ogl/ogledit/doc.cpp
3 // Purpose: Implements document functionality in OGLEdit
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 #include "wx/ioswrap.h"
25 #if !wxUSE_DOC_VIEW_ARCHITECTURE
26 #error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in wx_setup.h!
33 IMPLEMENT_DYNAMIC_CLASS(DiagramDocument
, wxDocument
)
35 DiagramDocument::DiagramDocument(void)
39 DiagramDocument::~DiagramDocument(void)
43 bool DiagramDocument::OnCloseDocument(void)
45 diagram
.DeleteAllShapes();
49 #if wxUSE_STD_IOSTREAM
50 wxSTD ostream
& DiagramDocument::SaveObject(wxSTD ostream
& stream
)
54 wxDocument::SaveObject(stream
);
57 (void) wxGetTempFileName("diag", buf
);
59 diagram
.SaveFile(buf
);
60 wxTransferFileToStream(buf
, stream
);
69 wxSTD istream
& DiagramDocument::LoadObject(wxSTD istream
& stream
)
73 wxDocument::LoadObject(stream
);
76 (void) wxGetTempFileName("diag", buf
);
78 wxTransferStreamToFile(stream
, buf
);
80 diagram
.DeleteAllShapes();
81 diagram
.LoadFile(buf
);
90 wxOutputStream
& DiagramDocument::SaveObject(wxOutputStream
& stream
)
94 wxDocument::SaveObject(stream
);
96 (void) wxGetTempFileName(_T("diag"), buf
);
98 diagram
.SaveFile(buf
);
100 wxTransferFileToStream(buf
, stream
);
109 wxInputStream
& DiagramDocument::LoadObject(wxInputStream
& stream
)
112 wxDocument::LoadObject(stream
);
115 (void) wxGetTempFileName(_T("diag"), buf
);
117 wxTransferStreamToFile(stream
, buf
);
119 diagram
.DeleteAllShapes();
120 diagram
.LoadFile(buf
);
130 * Implementation of drawing command
133 DiagramCommand::DiagramCommand(const wxString
& name
, int command
, DiagramDocument
*ddoc
, wxClassInfo
*info
, double xx
, double yy
,
134 bool sel
, wxShape
*theShape
, wxShape
*fs
, wxShape
*ts
)
135 :wxCommand(true, name
)
151 DiagramCommand::DiagramCommand(const wxString
& name
, int command
, DiagramDocument
*ddoc
, wxBrush
*backgroundColour
, wxShape
*theShape
)
152 :wxCommand(true, name
)
164 shapeBrush
= backgroundColour
;
168 DiagramCommand::DiagramCommand(const wxString
& name
, int command
, DiagramDocument
*ddoc
, const wxString
& lab
, wxShape
*theShape
)
169 :wxCommand(true, name
)
186 DiagramCommand::~DiagramCommand(void)
188 if (shape
&& deleteShape
)
190 shape
->SetCanvas(NULL
);
195 bool DiagramCommand::Do(void)
205 shape
->Select(false);
207 // Generate commands to explicitly remove each connected line.
210 doc
->GetDiagram()->RemoveShape(shape
);
211 if (shape
->IsKindOf(CLASSINFO(wxLineShape
)))
213 wxLineShape
*lineShape
= (wxLineShape
*)shape
;
214 fromShape
= lineShape
->GetFrom();
215 toShape
= lineShape
->GetTo();
220 doc
->UpdateAllViews();
225 case OGLEDIT_ADD_SHAPE
:
229 theShape
= shape
; // Saved from undoing the shape
232 theShape
= (wxShape
*)shapeInfo
->CreateObject();
233 theShape
->AssignNewIds();
234 theShape
->SetEventHandler(new MyEvtHandler(theShape
, theShape
, wxEmptyString
));
235 theShape
->SetCentreResize(false);
236 theShape
->SetPen(wxBLACK_PEN
);
237 theShape
->SetBrush(wxCYAN_BRUSH
);
239 theShape
->SetSize(60, 60);
241 doc
->GetDiagram()->AddShape(theShape
);
242 theShape
->Show(true);
244 wxClientDC
dc(theShape
->GetCanvas());
245 theShape
->GetCanvas()->PrepareDC(dc
);
247 theShape
->Move(dc
, x
, y
);
253 doc
->UpdateAllViews();
256 case OGLEDIT_ADD_LINE
:
260 theShape
= shape
; // Saved from undoing the line
263 theShape
= (wxShape
*)shapeInfo
->CreateObject();
264 theShape
->AssignNewIds();
265 theShape
->SetEventHandler(new MyEvtHandler(theShape
, theShape
, wxEmptyString
));
266 theShape
->SetPen(wxBLACK_PEN
);
267 theShape
->SetBrush(wxRED_BRUSH
);
269 wxLineShape
*lineShape
= (wxLineShape
*)theShape
;
271 // Yes, you can have more than 2 control points, in which case
272 // it becomes a multi-segment line.
273 lineShape
->MakeLineControlPoints(2);
274 lineShape
->AddArrow(ARROW_ARROW
, ARROW_POSITION_END
, 10.0, 0.0, _T("Normal arrowhead"));
277 doc
->GetDiagram()->AddShape(theShape
);
279 fromShape
->AddLine((wxLineShape
*)theShape
, toShape
);
281 theShape
->Show(true);
283 wxClientDC
dc(theShape
->GetCanvas());
284 theShape
->GetCanvas()->PrepareDC(dc
);
286 // It won't get drawn properly unless you move both
288 fromShape
->Move(dc
, fromShape
->GetX(), fromShape
->GetY());
289 toShape
->Move(dc
, toShape
->GetX(), toShape
->GetY());
295 doc
->UpdateAllViews();
298 case OGLEDIT_CHANGE_BACKGROUND_COLOUR
:
302 wxClientDC
dc(shape
->GetCanvas());
303 shape
->GetCanvas()->PrepareDC(dc
);
305 const wxBrush
*oldBrush
= shape
->GetBrush();
306 shape
->SetBrush(shapeBrush
);
307 shapeBrush
= oldBrush
;
311 doc
->UpdateAllViews();
316 case OGLEDIT_EDIT_LABEL
:
320 MyEvtHandler
*myHandler
= (MyEvtHandler
*)shape
->GetEventHandler();
321 wxString
oldLabel(myHandler
->label
);
322 myHandler
->label
= shapeLabel
;
323 shapeLabel
= oldLabel
;
325 wxClientDC
dc(shape
->GetCanvas());
326 shape
->GetCanvas()->PrepareDC(dc
);
328 shape
->FormatText(dc
, /* (char*) (const char*) */ myHandler
->label
);
332 doc
->UpdateAllViews();
341 bool DiagramCommand::Undo(void)
349 doc
->GetDiagram()->AddShape(shape
);
352 if (shape
->IsKindOf(CLASSINFO(wxLineShape
)))
354 wxLineShape
*lineShape
= (wxLineShape
*)shape
;
356 fromShape
->AddLine(lineShape
, toShape
);
364 doc
->UpdateAllViews();
367 case OGLEDIT_ADD_SHAPE
:
368 case OGLEDIT_ADD_LINE
:
372 wxClientDC
dc(shape
->GetCanvas());
373 shape
->GetCanvas()->PrepareDC(dc
);
375 shape
->Select(false, &dc
);
376 doc
->GetDiagram()->RemoveShape(shape
);
381 doc
->UpdateAllViews();
384 case OGLEDIT_CHANGE_BACKGROUND_COLOUR
:
388 wxClientDC
dc(shape
->GetCanvas());
389 shape
->GetCanvas()->PrepareDC(dc
);
391 const wxBrush
*oldBrush
= shape
->GetBrush();
392 shape
->SetBrush(shapeBrush
);
393 shapeBrush
= oldBrush
;
397 doc
->UpdateAllViews();
401 case OGLEDIT_EDIT_LABEL
:
405 MyEvtHandler
*myHandler
= (MyEvtHandler
*)shape
->GetEventHandler();
406 wxString
oldLabel(myHandler
->label
);
407 myHandler
->label
= shapeLabel
;
408 shapeLabel
= oldLabel
;
410 wxClientDC
dc(shape
->GetCanvas());
411 shape
->GetCanvas()->PrepareDC(dc
);
413 shape
->FormatText(dc
, /* (char*) (const char*) */ myHandler
->label
);
417 doc
->UpdateAllViews();
426 // Remove each individual line connected to a shape by sending a command.
427 void DiagramCommand::RemoveLines(wxShape
*shape
)
429 wxObjectList::compatibility_iterator node
= shape
->GetLines().GetFirst();
432 wxLineShape
*line
= (wxLineShape
*)node
->GetData();
433 doc
->GetCommandProcessor()->Submit(new DiagramCommand(_T("Cut"), wxID_CUT
, doc
, NULL
, 0.0, 0.0, line
->Selected(), line
));
435 node
= shape
->GetLines().GetFirst();
440 * MyEvtHandler: an event handler class for all shapes
443 void MyEvtHandler::OnLeftClick(double WXUNUSED(x
), double WXUNUSED(y
), int keys
, int WXUNUSED(attachment
))
445 wxClientDC
dc(GetShape()->GetCanvas());
446 GetShape()->GetCanvas()->PrepareDC(dc
);
450 // Selection is a concept the library knows about
451 if (GetShape()->Selected())
453 GetShape()->Select(false, &dc
);
454 GetShape()->GetCanvas()->Redraw(dc
); // Redraw because bits of objects will be are missing
458 // Ensure no other shape is selected, to simplify Undo/Redo code
460 wxObjectList::compatibility_iterator node
= GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->GetFirst();
463 wxShape
*eachShape
= (wxShape
*)node
->GetData();
464 if (eachShape
->GetParent() == NULL
)
466 if (eachShape
->Selected())
468 eachShape
->Select(false, &dc
);
472 node
= node
->GetNext();
474 GetShape()->Select(true, &dc
);
476 GetShape()->GetCanvas()->Redraw(dc
);
479 else if (keys
& KEY_CTRL
)
481 // Do something for CONTROL
486 wxGetApp().frame
->SetStatusText(label
);
487 #endif // wxUSE_STATUSBAR
492 * Implement connection of two shapes by right-dragging between them.
495 void MyEvtHandler::OnBeginDragRight(double x
, double y
, int WXUNUSED(keys
), int attachment
)
497 // Force attachment to be zero for now. Eventually we can deal with
498 // the actual attachment point, e.g. a rectangle side if attachment mode is on.
501 wxClientDC
dc(GetShape()->GetCanvas());
502 GetShape()->GetCanvas()->PrepareDC(dc
);
504 wxPen
dottedPen(*wxBLACK
, 1, wxDOT
);
505 dc
.SetLogicalFunction(OGLRBLF
);
506 dc
.SetPen(dottedPen
);
508 GetShape()->GetAttachmentPosition(attachment
, &xp
, &yp
);
509 dc
.DrawLine((long) xp
, (long) yp
, (long) x
, (long) y
);
510 GetShape()->GetCanvas()->CaptureMouse();
513 void MyEvtHandler::OnDragRight(bool WXUNUSED(draw
), double x
, double y
, int WXUNUSED(keys
), int attachment
)
515 // Force attachment to be zero for now
518 wxClientDC
dc(GetShape()->GetCanvas());
519 GetShape()->GetCanvas()->PrepareDC(dc
);
521 wxPen
dottedPen(*wxBLACK
, 1, wxDOT
);
522 dc
.SetLogicalFunction(OGLRBLF
);
523 dc
.SetPen(dottedPen
);
525 GetShape()->GetAttachmentPosition(attachment
, &xp
, &yp
);
526 dc
.DrawLine((long) xp
, (long) yp
, (long) x
, (long) y
);
529 void MyEvtHandler::OnEndDragRight(double x
, double y
, int WXUNUSED(keys
), int WXUNUSED(attachment
))
531 GetShape()->GetCanvas()->ReleaseMouse();
532 MyCanvas
*canvas
= (MyCanvas
*)GetShape()->GetCanvas();
534 // Check if we're on an object
536 wxShape
*otherShape
= canvas
->FindFirstSensitiveShape(x
, y
, &new_attachment
, OP_DRAG_RIGHT
);
538 if (otherShape
&& !otherShape
->IsKindOf(CLASSINFO(wxLineShape
)))
540 canvas
->view
->GetDocument()->GetCommandProcessor()->Submit(
541 new DiagramCommand(_T("wxLineShape"), OGLEDIT_ADD_LINE
, (DiagramDocument
*)canvas
->view
->GetDocument(), CLASSINFO(wxLineShape
),
542 0.0, 0.0, false, NULL
, GetShape(), otherShape
));
546 void MyEvtHandler::OnEndSize(double WXUNUSED(x
), double WXUNUSED(y
))
548 wxClientDC
dc(GetShape()->GetCanvas());
549 GetShape()->GetCanvas()->PrepareDC(dc
);
551 GetShape()->FormatText(dc
, /* (char*) (const char*) */ label
);
560 bool MyDiagram::OnShapeSave(wxExprDatabase
& db
, wxShape
& shape
, wxExpr
& expr
)
562 wxDiagram::OnShapeSave(db
, shape
, expr
);
563 MyEvtHandler
*handler
= (MyEvtHandler
*)shape
.GetEventHandler();
564 expr
.AddAttributeValueString(_T("label"), handler
->label
);
568 bool MyDiagram::OnShapeLoad(wxExprDatabase
& db
, wxShape
& shape
, wxExpr
& expr
)
570 wxDiagram::OnShapeLoad(db
, shape
, expr
);
571 wxChar
*label
= NULL
;
572 expr
.AssignAttributeValue(_T("label"), &label
);
573 MyEvtHandler
*handler
= new MyEvtHandler(&shape
, &shape
, wxString(label
));
574 shape
.SetEventHandler(handler
);
587 IMPLEMENT_DYNAMIC_CLASS(wxRoundedRectangleShape
, wxRectangleShape
)
589 wxRoundedRectangleShape::wxRoundedRectangleShape(double w
, double h
):
590 wxRectangleShape(w
, h
)
592 // 0.3 of the smaller rectangle dimension
593 SetCornerRadius((double) -0.3);
596 IMPLEMENT_DYNAMIC_CLASS(wxDiamondShape
, wxPolygonShape
)
598 wxDiamondShape::wxDiamondShape(double w
, double h
):
601 // wxPolygonShape::SetSize relies on the shape having non-zero
608 wxList
*thePoints
= new wxList
;
609 wxRealPoint
*point
= new wxRealPoint(0.0, (-h
/2.0));
610 thePoints
->Append((wxObject
*) point
);
612 point
= new wxRealPoint((w
/2.0), 0.0);
613 thePoints
->Append((wxObject
*) point
);
615 point
= new wxRealPoint(0.0, (h
/2.0));
616 thePoints
->Append((wxObject
*) point
);
618 point
= new wxRealPoint((-w
/2.0), 0.0);
619 thePoints
->Append((wxObject
*) point
);