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!
31 #include <wx/wxexpr.h>
36 #if wxUSE_STD_IOSTREAM
40 IMPLEMENT_DYNAMIC_CLASS(DiagramDocument
, wxDocument
)
42 DiagramDocument::DiagramDocument(void)
46 DiagramDocument::~DiagramDocument(void)
50 bool DiagramDocument::OnCloseDocument(void)
52 diagram
.DeleteAllShapes();
56 #if wxUSE_STD_IOSTREAM
57 ostream
& DiagramDocument::SaveObject(ostream
& stream
)
59 wxDocument::SaveObject(stream
);
62 (void) wxGetTempFileName("diag", buf
);
64 diagram
.SaveFile(buf
);
65 wxTransferFileToStream(buf
, stream
);
72 istream
& DiagramDocument::LoadObject(istream
& stream
)
74 wxDocument::LoadObject(stream
);
77 (void) wxGetTempFileName("diag", buf
);
79 wxTransferStreamToFile(stream
, buf
);
81 diagram
.DeleteAllShapes();
82 diagram
.LoadFile(buf
);
89 wxOutputStream
& DiagramDocument::SaveObject(wxOutputStream
& stream
)
91 wxDocument::SaveObject(stream
);
93 (void) wxGetTempFileName("diag", buf
);
95 diagram
.SaveFile(buf
);
97 wxTransferFileToStream(buf
, stream
);
105 wxInputStream
& DiagramDocument::LoadObject(wxInputStream
& stream
)
107 wxDocument::LoadObject(stream
);
111 (void) wxGetTempFileName("diag", buf
);
113 wxTransferStreamToFile(stream
, buf
);
115 diagram
.DeleteAllShapes();
116 diagram
.LoadFile(buf
);
125 * Implementation of drawing command
128 DiagramCommand::DiagramCommand(char *name
, int command
, DiagramDocument
*ddoc
, wxClassInfo
*info
, double xx
, double yy
,
129 bool sel
, wxShape
*theShape
, wxShape
*fs
, wxShape
*ts
):
130 wxCommand(TRUE
, name
)
146 DiagramCommand::DiagramCommand(char *name
, int command
, DiagramDocument
*ddoc
, wxBrush
*backgroundColour
, wxShape
*theShape
):
147 wxCommand(TRUE
, name
)
159 shapeBrush
= backgroundColour
;
163 DiagramCommand::DiagramCommand(char *name
, int command
, DiagramDocument
*ddoc
, const wxString
& lab
, wxShape
*theShape
):
164 wxCommand(TRUE
, name
)
181 DiagramCommand::~DiagramCommand(void)
183 if (shape
&& deleteShape
)
185 shape
->SetCanvas(NULL
);
190 bool DiagramCommand::Do(void)
200 shape
->Select(FALSE
);
202 // Generate commands to explicitly remove each connected line.
205 doc
->GetDiagram()->RemoveShape(shape
);
206 if (shape
->IsKindOf(CLASSINFO(wxLineShape
)))
208 wxLineShape
*lineShape
= (wxLineShape
*)shape
;
209 fromShape
= lineShape
->GetFrom();
210 toShape
= lineShape
->GetTo();
215 doc
->UpdateAllViews();
220 case OGLEDIT_ADD_SHAPE
:
222 wxShape
*theShape
= NULL
;
224 theShape
= shape
; // Saved from undoing the shape
227 theShape
= (wxShape
*)shapeInfo
->CreateObject();
228 theShape
->AssignNewIds();
229 theShape
->SetEventHandler(new MyEvtHandler(theShape
, theShape
, wxString("")));
230 theShape
->SetCentreResize(FALSE
);
231 theShape
->SetPen(wxBLACK_PEN
);
232 theShape
->SetBrush(wxCYAN_BRUSH
);
234 theShape
->SetSize(60, 60);
236 doc
->GetDiagram()->AddShape(theShape
);
237 theShape
->Show(TRUE
);
239 wxClientDC
dc(theShape
->GetCanvas());
240 theShape
->GetCanvas()->PrepareDC(dc
);
242 theShape
->Move(dc
, x
, y
);
248 doc
->UpdateAllViews();
251 case OGLEDIT_ADD_LINE
:
253 wxShape
*theShape
= NULL
;
255 theShape
= shape
; // Saved from undoing the line
258 theShape
= (wxShape
*)shapeInfo
->CreateObject();
259 theShape
->AssignNewIds();
260 theShape
->SetEventHandler(new MyEvtHandler(theShape
, theShape
, wxString("")));
261 theShape
->SetPen(wxBLACK_PEN
);
262 theShape
->SetBrush(wxRED_BRUSH
);
264 wxLineShape
*lineShape
= (wxLineShape
*)theShape
;
266 // Yes, you can have more than 2 control points, in which case
267 // it becomes a multi-segment line.
268 lineShape
->MakeLineControlPoints(2);
269 lineShape
->AddArrow(ARROW_ARROW
, ARROW_POSITION_END
, 10.0, 0.0, "Normal arrowhead");
272 doc
->GetDiagram()->AddShape(theShape
);
274 fromShape
->AddLine((wxLineShape
*)theShape
, toShape
);
276 theShape
->Show(TRUE
);
278 wxClientDC
dc(theShape
->GetCanvas());
279 theShape
->GetCanvas()->PrepareDC(dc
);
281 // It won't get drawn properly unless you move both
283 fromShape
->Move(dc
, fromShape
->GetX(), fromShape
->GetY());
284 toShape
->Move(dc
, toShape
->GetX(), toShape
->GetY());
290 doc
->UpdateAllViews();
293 case OGLEDIT_CHANGE_BACKGROUND_COLOUR
:
297 wxClientDC
dc(shape
->GetCanvas());
298 shape
->GetCanvas()->PrepareDC(dc
);
300 wxBrush
*oldBrush
= shape
->GetBrush();
301 shape
->SetBrush(shapeBrush
);
302 shapeBrush
= oldBrush
;
306 doc
->UpdateAllViews();
311 case OGLEDIT_EDIT_LABEL
:
315 MyEvtHandler
*myHandler
= (MyEvtHandler
*)shape
->GetEventHandler();
316 wxString
oldLabel(myHandler
->label
);
317 myHandler
->label
= shapeLabel
;
318 shapeLabel
= oldLabel
;
320 wxClientDC
dc(shape
->GetCanvas());
321 shape
->GetCanvas()->PrepareDC(dc
);
323 shape
->FormatText(dc
, (char*) (const char*) myHandler
->label
);
327 doc
->UpdateAllViews();
336 bool DiagramCommand::Undo(void)
344 doc
->GetDiagram()->AddShape(shape
);
347 if (shape
->IsKindOf(CLASSINFO(wxLineShape
)))
349 wxLineShape
*lineShape
= (wxLineShape
*)shape
;
351 fromShape
->AddLine(lineShape
, toShape
);
359 doc
->UpdateAllViews();
362 case OGLEDIT_ADD_SHAPE
:
363 case OGLEDIT_ADD_LINE
:
367 wxClientDC
dc(shape
->GetCanvas());
368 shape
->GetCanvas()->PrepareDC(dc
);
370 shape
->Select(FALSE
, &dc
);
371 doc
->GetDiagram()->RemoveShape(shape
);
376 doc
->UpdateAllViews();
379 case OGLEDIT_CHANGE_BACKGROUND_COLOUR
:
383 wxClientDC
dc(shape
->GetCanvas());
384 shape
->GetCanvas()->PrepareDC(dc
);
386 wxBrush
*oldBrush
= shape
->GetBrush();
387 shape
->SetBrush(shapeBrush
);
388 shapeBrush
= oldBrush
;
392 doc
->UpdateAllViews();
396 case OGLEDIT_EDIT_LABEL
:
400 MyEvtHandler
*myHandler
= (MyEvtHandler
*)shape
->GetEventHandler();
401 wxString
oldLabel(myHandler
->label
);
402 myHandler
->label
= shapeLabel
;
403 shapeLabel
= oldLabel
;
405 wxClientDC
dc(shape
->GetCanvas());
406 shape
->GetCanvas()->PrepareDC(dc
);
408 shape
->FormatText(dc
, (char*) (const char*) myHandler
->label
);
412 doc
->UpdateAllViews();
421 // Remove each individual line connected to a shape by sending a command.
422 void DiagramCommand::RemoveLines(wxShape
*shape
)
424 wxNode
*node
= shape
->GetLines().First();
427 wxLineShape
*line
= (wxLineShape
*)node
->Data();
428 doc
->GetCommandProcessor()->Submit(new DiagramCommand("Cut", OGLEDIT_CUT
, doc
, NULL
, 0.0, 0.0, line
->Selected(), line
));
430 node
= shape
->GetLines().First();
435 * MyEvtHandler: an event handler class for all shapes
438 void MyEvtHandler::OnLeftClick(double x
, double y
, int keys
, int attachment
)
440 wxClientDC
dc(GetShape()->GetCanvas());
441 GetShape()->GetCanvas()->PrepareDC(dc
);
445 // Selection is a concept the library knows about
446 if (GetShape()->Selected())
448 GetShape()->Select(FALSE
, &dc
);
449 GetShape()->GetCanvas()->Redraw(dc
); // Redraw because bits of objects will be are missing
453 // Ensure no other shape is selected, to simplify Undo/Redo code
455 wxNode
*node
= GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->First();
458 wxShape
*eachShape
= (wxShape
*)node
->Data();
459 if (eachShape
->GetParent() == NULL
)
461 if (eachShape
->Selected())
463 eachShape
->Select(FALSE
, &dc
);
469 GetShape()->Select(TRUE
, &dc
);
471 GetShape()->GetCanvas()->Redraw(dc
);
474 else if (keys
& KEY_CTRL
)
476 // Do something for CONTROL
480 wxGetApp().frame
->SetStatusText(label
);
485 * Implement connection of two shapes by right-dragging between them.
488 void MyEvtHandler::OnBeginDragRight(double x
, double y
, int keys
, int attachment
)
490 // Force attachment to be zero for now. Eventually we can deal with
491 // the actual attachment point, e.g. a rectangle side if attachment mode is on.
494 wxClientDC
dc(GetShape()->GetCanvas());
495 GetShape()->GetCanvas()->PrepareDC(dc
);
497 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
498 dc
.SetLogicalFunction(OGLRBLF
);
499 dc
.SetPen(dottedPen
);
501 GetShape()->GetAttachmentPosition(attachment
, &xp
, &yp
);
502 dc
.DrawLine((long) xp
, (long) yp
, (long) x
, (long) y
);
503 GetShape()->GetCanvas()->CaptureMouse();
506 void MyEvtHandler::OnDragRight(bool draw
, double x
, double y
, int keys
, int attachment
)
508 // Force attachment to be zero for now
511 wxClientDC
dc(GetShape()->GetCanvas());
512 GetShape()->GetCanvas()->PrepareDC(dc
);
514 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
515 dc
.SetLogicalFunction(OGLRBLF
);
516 dc
.SetPen(dottedPen
);
518 GetShape()->GetAttachmentPosition(attachment
, &xp
, &yp
);
519 dc
.DrawLine((long) xp
, (long) yp
, (long) x
, (long) y
);
522 void MyEvtHandler::OnEndDragRight(double x
, double y
, int keys
, int attachment
)
524 GetShape()->GetCanvas()->ReleaseMouse();
525 MyCanvas
*canvas
= (MyCanvas
*)GetShape()->GetCanvas();
527 // Check if we're on an object
529 wxShape
*otherShape
= canvas
->FindFirstSensitiveShape(x
, y
, &new_attachment
, OP_DRAG_RIGHT
);
531 if (otherShape
&& !otherShape
->IsKindOf(CLASSINFO(wxLineShape
)))
533 canvas
->view
->GetDocument()->GetCommandProcessor()->Submit(
534 new DiagramCommand("wxLineShape", OGLEDIT_ADD_LINE
, (DiagramDocument
*)canvas
->view
->GetDocument(), CLASSINFO(wxLineShape
),
535 0.0, 0.0, FALSE
, NULL
, GetShape(), otherShape
));
539 void MyEvtHandler::OnEndSize(double x
, double y
)
541 wxClientDC
dc(GetShape()->GetCanvas());
542 GetShape()->GetCanvas()->PrepareDC(dc
);
544 GetShape()->FormatText(dc
, (char*) (const char*) label
);
551 bool MyDiagram::OnShapeSave(wxExprDatabase
& db
, wxShape
& shape
, wxExpr
& expr
)
553 wxDiagram::OnShapeSave(db
, shape
, expr
);
554 MyEvtHandler
*handler
= (MyEvtHandler
*)shape
.GetEventHandler();
555 expr
.AddAttributeValueString("label", handler
->label
);
559 bool MyDiagram::OnShapeLoad(wxExprDatabase
& db
, wxShape
& shape
, wxExpr
& expr
)
561 wxDiagram::OnShapeLoad(db
, shape
, expr
);
563 expr
.AssignAttributeValue("label", &label
);
564 MyEvtHandler
*handler
= new MyEvtHandler(&shape
, &shape
, wxString(label
));
565 shape
.SetEventHandler(handler
);
576 IMPLEMENT_DYNAMIC_CLASS(wxRoundedRectangleShape
, wxRectangleShape
)
578 wxRoundedRectangleShape::wxRoundedRectangleShape(double w
, double h
):
579 wxRectangleShape(w
, h
)
581 // 0.3 of the smaller rectangle dimension
582 SetCornerRadius((double) -0.3);
585 IMPLEMENT_DYNAMIC_CLASS(wxDiamondShape
, wxPolygonShape
)
587 wxDiamondShape::wxDiamondShape(double w
, double h
):
590 // wxPolygonShape::SetSize relies on the shape having non-zero
597 wxList
*thePoints
= new wxList
;
598 wxRealPoint
*point
= new wxRealPoint(0.0, (-h
/2.0));
599 thePoints
->Append((wxObject
*) point
);
601 point
= new wxRealPoint((w
/2.0), 0.0);
602 thePoints
->Append((wxObject
*) point
);
604 point
= new wxRealPoint(0.0, (h
/2.0));
605 thePoints
->Append((wxObject
*) point
);
607 point
= new wxRealPoint((-w
/2.0), 0.0);
608 thePoints
->Append((wxObject
*) point
);