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 #if !wxUSE_DOC_VIEW_ARCHITECTURE
28 #error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in wx_setup.h!
35 #if wxUSE_STD_IOSTREAM
39 IMPLEMENT_DYNAMIC_CLASS(DiagramDocument
, wxDocument
)
41 DiagramDocument::DiagramDocument(void)
45 DiagramDocument::~DiagramDocument(void)
49 bool DiagramDocument::OnCloseDocument(void)
51 diagram
.DeleteAllShapes();
55 #if wxUSE_STD_IOSTREAM
56 wxSTD ostream
& DiagramDocument::SaveObject(wxSTD ostream
& stream
)
58 wxDocument::SaveObject(stream
);
61 (void) wxGetTempFileName("diag", buf
);
63 diagram
.SaveFile(buf
);
64 wxTransferFileToStream(buf
, stream
);
71 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
);
88 wxOutputStream
& DiagramDocument::SaveObject(wxOutputStream
& stream
)
90 wxDocument::SaveObject(stream
);
92 (void) wxGetTempFileName("diag", buf
);
94 diagram
.SaveFile(buf
);
96 wxTransferFileToStream(buf
, stream
);
104 wxInputStream
& DiagramDocument::LoadObject(wxInputStream
& stream
)
106 wxDocument::LoadObject(stream
);
110 (void) wxGetTempFileName("diag", buf
);
112 wxTransferStreamToFile(stream
, buf
);
114 diagram
.DeleteAllShapes();
115 diagram
.LoadFile(buf
);
124 * Implementation of drawing command
127 DiagramCommand::DiagramCommand(char *name
, int command
, DiagramDocument
*ddoc
, wxClassInfo
*info
, double xx
, double yy
,
128 bool sel
, wxShape
*theShape
, wxShape
*fs
, wxShape
*ts
):
129 wxCommand(TRUE
, name
)
145 DiagramCommand::DiagramCommand(char *name
, int command
, DiagramDocument
*ddoc
, wxBrush
*backgroundColour
, wxShape
*theShape
):
146 wxCommand(TRUE
, name
)
158 shapeBrush
= backgroundColour
;
162 DiagramCommand::DiagramCommand(char *name
, int command
, DiagramDocument
*ddoc
, const wxString
& lab
, wxShape
*theShape
):
163 wxCommand(TRUE
, name
)
180 DiagramCommand::~DiagramCommand(void)
182 if (shape
&& deleteShape
)
184 shape
->SetCanvas(NULL
);
189 bool DiagramCommand::Do(void)
199 shape
->Select(FALSE
);
201 // Generate commands to explicitly remove each connected line.
204 doc
->GetDiagram()->RemoveShape(shape
);
205 if (shape
->IsKindOf(CLASSINFO(wxLineShape
)))
207 wxLineShape
*lineShape
= (wxLineShape
*)shape
;
208 fromShape
= lineShape
->GetFrom();
209 toShape
= lineShape
->GetTo();
214 doc
->UpdateAllViews();
219 case OGLEDIT_ADD_SHAPE
:
221 wxShape
*theShape
= NULL
;
223 theShape
= shape
; // Saved from undoing the shape
226 theShape
= (wxShape
*)shapeInfo
->CreateObject();
227 theShape
->AssignNewIds();
228 theShape
->SetEventHandler(new MyEvtHandler(theShape
, theShape
, wxString("")));
229 theShape
->SetCentreResize(FALSE
);
230 theShape
->SetPen(wxBLACK_PEN
);
231 theShape
->SetBrush(wxCYAN_BRUSH
);
233 theShape
->SetSize(60, 60);
235 doc
->GetDiagram()->AddShape(theShape
);
236 theShape
->Show(TRUE
);
238 wxClientDC
dc(theShape
->GetCanvas());
239 theShape
->GetCanvas()->PrepareDC(dc
);
241 theShape
->Move(dc
, x
, y
);
247 doc
->UpdateAllViews();
250 case OGLEDIT_ADD_LINE
:
252 wxShape
*theShape
= NULL
;
254 theShape
= shape
; // Saved from undoing the line
257 theShape
= (wxShape
*)shapeInfo
->CreateObject();
258 theShape
->AssignNewIds();
259 theShape
->SetEventHandler(new MyEvtHandler(theShape
, theShape
, wxString("")));
260 theShape
->SetPen(wxBLACK_PEN
);
261 theShape
->SetBrush(wxRED_BRUSH
);
263 wxLineShape
*lineShape
= (wxLineShape
*)theShape
;
265 // Yes, you can have more than 2 control points, in which case
266 // it becomes a multi-segment line.
267 lineShape
->MakeLineControlPoints(2);
268 lineShape
->AddArrow(ARROW_ARROW
, ARROW_POSITION_END
, 10.0, 0.0, "Normal arrowhead");
271 doc
->GetDiagram()->AddShape(theShape
);
273 fromShape
->AddLine((wxLineShape
*)theShape
, toShape
);
275 theShape
->Show(TRUE
);
277 wxClientDC
dc(theShape
->GetCanvas());
278 theShape
->GetCanvas()->PrepareDC(dc
);
280 // It won't get drawn properly unless you move both
282 fromShape
->Move(dc
, fromShape
->GetX(), fromShape
->GetY());
283 toShape
->Move(dc
, toShape
->GetX(), toShape
->GetY());
289 doc
->UpdateAllViews();
292 case OGLEDIT_CHANGE_BACKGROUND_COLOUR
:
296 wxClientDC
dc(shape
->GetCanvas());
297 shape
->GetCanvas()->PrepareDC(dc
);
299 wxBrush
*oldBrush
= shape
->GetBrush();
300 shape
->SetBrush(shapeBrush
);
301 shapeBrush
= oldBrush
;
305 doc
->UpdateAllViews();
310 case OGLEDIT_EDIT_LABEL
:
314 MyEvtHandler
*myHandler
= (MyEvtHandler
*)shape
->GetEventHandler();
315 wxString
oldLabel(myHandler
->label
);
316 myHandler
->label
= shapeLabel
;
317 shapeLabel
= oldLabel
;
319 wxClientDC
dc(shape
->GetCanvas());
320 shape
->GetCanvas()->PrepareDC(dc
);
322 shape
->FormatText(dc
, (char*) (const char*) myHandler
->label
);
326 doc
->UpdateAllViews();
335 bool DiagramCommand::Undo(void)
343 doc
->GetDiagram()->AddShape(shape
);
346 if (shape
->IsKindOf(CLASSINFO(wxLineShape
)))
348 wxLineShape
*lineShape
= (wxLineShape
*)shape
;
350 fromShape
->AddLine(lineShape
, toShape
);
358 doc
->UpdateAllViews();
361 case OGLEDIT_ADD_SHAPE
:
362 case OGLEDIT_ADD_LINE
:
366 wxClientDC
dc(shape
->GetCanvas());
367 shape
->GetCanvas()->PrepareDC(dc
);
369 shape
->Select(FALSE
, &dc
);
370 doc
->GetDiagram()->RemoveShape(shape
);
375 doc
->UpdateAllViews();
378 case OGLEDIT_CHANGE_BACKGROUND_COLOUR
:
382 wxClientDC
dc(shape
->GetCanvas());
383 shape
->GetCanvas()->PrepareDC(dc
);
385 wxBrush
*oldBrush
= shape
->GetBrush();
386 shape
->SetBrush(shapeBrush
);
387 shapeBrush
= oldBrush
;
391 doc
->UpdateAllViews();
395 case OGLEDIT_EDIT_LABEL
:
399 MyEvtHandler
*myHandler
= (MyEvtHandler
*)shape
->GetEventHandler();
400 wxString
oldLabel(myHandler
->label
);
401 myHandler
->label
= shapeLabel
;
402 shapeLabel
= oldLabel
;
404 wxClientDC
dc(shape
->GetCanvas());
405 shape
->GetCanvas()->PrepareDC(dc
);
407 shape
->FormatText(dc
, (char*) (const char*) myHandler
->label
);
411 doc
->UpdateAllViews();
420 // Remove each individual line connected to a shape by sending a command.
421 void DiagramCommand::RemoveLines(wxShape
*shape
)
423 wxNode
*node
= shape
->GetLines().First();
426 wxLineShape
*line
= (wxLineShape
*)node
->Data();
427 doc
->GetCommandProcessor()->Submit(new DiagramCommand("Cut", OGLEDIT_CUT
, doc
, NULL
, 0.0, 0.0, line
->Selected(), line
));
429 node
= shape
->GetLines().First();
434 * MyEvtHandler: an event handler class for all shapes
437 void MyEvtHandler::OnLeftClick(double x
, double y
, int keys
, int attachment
)
439 wxClientDC
dc(GetShape()->GetCanvas());
440 GetShape()->GetCanvas()->PrepareDC(dc
);
444 // Selection is a concept the library knows about
445 if (GetShape()->Selected())
447 GetShape()->Select(FALSE
, &dc
);
448 GetShape()->GetCanvas()->Redraw(dc
); // Redraw because bits of objects will be are missing
452 // Ensure no other shape is selected, to simplify Undo/Redo code
454 wxNode
*node
= GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->First();
457 wxShape
*eachShape
= (wxShape
*)node
->Data();
458 if (eachShape
->GetParent() == NULL
)
460 if (eachShape
->Selected())
462 eachShape
->Select(FALSE
, &dc
);
468 GetShape()->Select(TRUE
, &dc
);
470 GetShape()->GetCanvas()->Redraw(dc
);
473 else if (keys
& KEY_CTRL
)
475 // Do something for CONTROL
479 wxGetApp().frame
->SetStatusText(label
);
484 * Implement connection of two shapes by right-dragging between them.
487 void MyEvtHandler::OnBeginDragRight(double x
, double y
, int keys
, int attachment
)
489 // Force attachment to be zero for now. Eventually we can deal with
490 // the actual attachment point, e.g. a rectangle side if attachment mode is on.
493 wxClientDC
dc(GetShape()->GetCanvas());
494 GetShape()->GetCanvas()->PrepareDC(dc
);
496 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
497 dc
.SetLogicalFunction(OGLRBLF
);
498 dc
.SetPen(dottedPen
);
500 GetShape()->GetAttachmentPosition(attachment
, &xp
, &yp
);
501 dc
.DrawLine((long) xp
, (long) yp
, (long) x
, (long) y
);
502 GetShape()->GetCanvas()->CaptureMouse();
505 void MyEvtHandler::OnDragRight(bool draw
, double x
, double y
, int keys
, int attachment
)
507 // Force attachment to be zero for now
510 wxClientDC
dc(GetShape()->GetCanvas());
511 GetShape()->GetCanvas()->PrepareDC(dc
);
513 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
514 dc
.SetLogicalFunction(OGLRBLF
);
515 dc
.SetPen(dottedPen
);
517 GetShape()->GetAttachmentPosition(attachment
, &xp
, &yp
);
518 dc
.DrawLine((long) xp
, (long) yp
, (long) x
, (long) y
);
521 void MyEvtHandler::OnEndDragRight(double x
, double y
, int keys
, int attachment
)
523 GetShape()->GetCanvas()->ReleaseMouse();
524 MyCanvas
*canvas
= (MyCanvas
*)GetShape()->GetCanvas();
526 // Check if we're on an object
528 wxShape
*otherShape
= canvas
->FindFirstSensitiveShape(x
, y
, &new_attachment
, OP_DRAG_RIGHT
);
530 if (otherShape
&& !otherShape
->IsKindOf(CLASSINFO(wxLineShape
)))
532 canvas
->view
->GetDocument()->GetCommandProcessor()->Submit(
533 new DiagramCommand("wxLineShape", OGLEDIT_ADD_LINE
, (DiagramDocument
*)canvas
->view
->GetDocument(), CLASSINFO(wxLineShape
),
534 0.0, 0.0, FALSE
, NULL
, GetShape(), otherShape
));
538 void MyEvtHandler::OnEndSize(double x
, double y
)
540 wxClientDC
dc(GetShape()->GetCanvas());
541 GetShape()->GetCanvas()->PrepareDC(dc
);
543 GetShape()->FormatText(dc
, (char*) (const char*) label
);
550 bool MyDiagram::OnShapeSave(wxExprDatabase
& db
, wxShape
& shape
, wxExpr
& expr
)
552 wxDiagram::OnShapeSave(db
, shape
, expr
);
553 MyEvtHandler
*handler
= (MyEvtHandler
*)shape
.GetEventHandler();
554 expr
.AddAttributeValueString("label", handler
->label
);
558 bool MyDiagram::OnShapeLoad(wxExprDatabase
& db
, wxShape
& shape
, wxExpr
& expr
)
560 wxDiagram::OnShapeLoad(db
, shape
, expr
);
562 expr
.AssignAttributeValue("label", &label
);
563 MyEvtHandler
*handler
= new MyEvtHandler(&shape
, &shape
, wxString(label
));
564 shape
.SetEventHandler(handler
);
575 IMPLEMENT_DYNAMIC_CLASS(wxRoundedRectangleShape
, wxRectangleShape
)
577 wxRoundedRectangleShape::wxRoundedRectangleShape(double w
, double h
):
578 wxRectangleShape(w
, h
)
580 // 0.3 of the smaller rectangle dimension
581 SetCornerRadius((double) -0.3);
584 IMPLEMENT_DYNAMIC_CLASS(wxDiamondShape
, wxPolygonShape
)
586 wxDiamondShape::wxDiamondShape(double w
, double h
):
589 // wxPolygonShape::SetSize relies on the shape having non-zero
596 wxList
*thePoints
= new wxList
;
597 wxRealPoint
*point
= new wxRealPoint(0.0, (-h
/2.0));
598 thePoints
->Append((wxObject
*) point
);
600 point
= new wxRealPoint((w
/2.0), 0.0);
601 thePoints
->Append((wxObject
*) point
);
603 point
= new wxRealPoint(0.0, (h
/2.0));
604 thePoints
->Append((wxObject
*) point
);
606 point
= new wxRealPoint((-w
/2.0), 0.0);
607 thePoints
->Append((wxObject
*) point
);