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 !USE_DOC_VIEW_ARCHITECTURE
28 #error You must set USE_DOC_VIEW_ARCHITECTURE to 1 in wx_setup.h!
33 #include <wx/wxexpr.h>
36 IMPLEMENT_DYNAMIC_CLASS(DiagramDocument
, wxDocument
)
38 DiagramDocument::DiagramDocument(void)
42 DiagramDocument::~DiagramDocument(void)
46 bool DiagramDocument::OnCloseDocument(void)
48 diagram
.DeleteAllShapes();
52 ostream
& DiagramDocument::SaveObject(ostream
& stream
)
54 wxDocument::SaveObject(stream
);
57 (void) wxGetTempFileName("diag", buf
);
59 diagram
.SaveFile(buf
);
60 wxTransferFileToStream(buf
, stream
);
67 istream
& DiagramDocument::LoadObject(istream
& stream
)
69 wxDocument::LoadObject(stream
);
72 (void) wxGetTempFileName("diag", buf
);
74 wxTransferStreamToFile(stream
, buf
);
76 diagram
.DeleteAllShapes();
77 diagram
.LoadFile(buf
);
84 * Implementation of drawing command
87 DiagramCommand::DiagramCommand(char *name
, int command
, DiagramDocument
*ddoc
, wxClassInfo
*info
, double xx
, double yy
,
88 bool sel
, wxShape
*theShape
, wxShape
*fs
, wxShape
*ts
):
105 DiagramCommand::DiagramCommand(char *name
, int command
, DiagramDocument
*ddoc
, wxBrush
*backgroundColour
, wxShape
*theShape
):
106 wxCommand(TRUE
, name
)
118 shapeBrush
= backgroundColour
;
122 DiagramCommand::DiagramCommand(char *name
, int command
, DiagramDocument
*ddoc
, const wxString
& lab
, wxShape
*theShape
):
123 wxCommand(TRUE
, name
)
140 DiagramCommand::~DiagramCommand(void)
142 if (shape
&& deleteShape
)
144 shape
->SetCanvas(NULL
);
149 bool DiagramCommand::Do(void)
159 shape
->Select(FALSE
);
161 // Generate commands to explicitly remove each connected line.
164 doc
->GetDiagram()->RemoveShape(shape
);
165 if (shape
->IsKindOf(CLASSINFO(wxLineShape
)))
167 wxLineShape
*lineShape
= (wxLineShape
*)shape
;
168 fromShape
= lineShape
->GetFrom();
169 toShape
= lineShape
->GetTo();
174 doc
->UpdateAllViews();
179 case OGLEDIT_ADD_SHAPE
:
181 wxShape
*theShape
= NULL
;
183 theShape
= shape
; // Saved from undoing the shape
186 theShape
= (wxShape
*)shapeInfo
->CreateObject();
187 theShape
->AssignNewIds();
188 theShape
->SetEventHandler(new MyEvtHandler(theShape
, theShape
, wxString("")));
189 theShape
->SetCentreResize(FALSE
);
190 theShape
->SetPen(wxBLACK_PEN
);
191 theShape
->SetBrush(wxCYAN_BRUSH
);
193 theShape
->SetSize(60, 60);
195 doc
->GetDiagram()->AddShape(theShape
);
196 theShape
->Show(TRUE
);
198 wxClientDC
dc(theShape
->GetCanvas());
199 theShape
->GetCanvas()->PrepareDC(dc
);
201 theShape
->Move(dc
, x
, y
);
207 doc
->UpdateAllViews();
210 case OGLEDIT_ADD_LINE
:
212 wxShape
*theShape
= NULL
;
214 theShape
= shape
; // Saved from undoing the line
217 theShape
= (wxShape
*)shapeInfo
->CreateObject();
218 theShape
->AssignNewIds();
219 theShape
->SetEventHandler(new MyEvtHandler(theShape
, theShape
, wxString("")));
220 theShape
->SetPen(wxBLACK_PEN
);
221 theShape
->SetBrush(wxRED_BRUSH
);
223 wxLineShape
*lineShape
= (wxLineShape
*)theShape
;
225 // Yes, you can have more than 2 control points, in which case
226 // it becomes a multi-segment line.
227 lineShape
->MakeLineControlPoints(2);
228 lineShape
->AddArrow(ARROW_ARROW
, ARROW_POSITION_END
, 10.0, 0.0, "Normal arrowhead");
231 doc
->GetDiagram()->AddShape(theShape
);
233 fromShape
->AddLine((wxLineShape
*)theShape
, toShape
);
235 theShape
->Show(TRUE
);
237 wxClientDC
dc(theShape
->GetCanvas());
238 theShape
->GetCanvas()->PrepareDC(dc
);
240 // It won't get drawn properly unless you move both
242 fromShape
->Move(dc
, fromShape
->GetX(), fromShape
->GetY());
243 toShape
->Move(dc
, toShape
->GetX(), toShape
->GetY());
249 doc
->UpdateAllViews();
252 case OGLEDIT_CHANGE_BACKGROUND_COLOUR
:
256 wxClientDC
dc(shape
->GetCanvas());
257 shape
->GetCanvas()->PrepareDC(dc
);
259 wxBrush
*oldBrush
= shape
->GetBrush();
260 shape
->SetBrush(shapeBrush
);
261 shapeBrush
= oldBrush
;
265 doc
->UpdateAllViews();
270 case OGLEDIT_EDIT_LABEL
:
274 MyEvtHandler
*myHandler
= (MyEvtHandler
*)shape
->GetEventHandler();
275 wxString
oldLabel(myHandler
->label
);
276 myHandler
->label
= shapeLabel
;
277 shapeLabel
= oldLabel
;
279 wxClientDC
dc(shape
->GetCanvas());
280 shape
->GetCanvas()->PrepareDC(dc
);
282 shape
->FormatText(dc
, (char*) (const char*) myHandler
->label
);
286 doc
->UpdateAllViews();
295 bool DiagramCommand::Undo(void)
303 doc
->GetDiagram()->AddShape(shape
);
306 if (shape
->IsKindOf(CLASSINFO(wxLineShape
)))
308 wxLineShape
*lineShape
= (wxLineShape
*)shape
;
310 fromShape
->AddLine(lineShape
, toShape
);
318 doc
->UpdateAllViews();
321 case OGLEDIT_ADD_SHAPE
:
322 case OGLEDIT_ADD_LINE
:
326 wxClientDC
dc(shape
->GetCanvas());
327 shape
->GetCanvas()->PrepareDC(dc
);
329 shape
->Select(FALSE
, &dc
);
330 doc
->GetDiagram()->RemoveShape(shape
);
335 doc
->UpdateAllViews();
338 case OGLEDIT_CHANGE_BACKGROUND_COLOUR
:
342 wxClientDC
dc(shape
->GetCanvas());
343 shape
->GetCanvas()->PrepareDC(dc
);
345 wxBrush
*oldBrush
= shape
->GetBrush();
346 shape
->SetBrush(shapeBrush
);
347 shapeBrush
= oldBrush
;
351 doc
->UpdateAllViews();
355 case OGLEDIT_EDIT_LABEL
:
359 MyEvtHandler
*myHandler
= (MyEvtHandler
*)shape
->GetEventHandler();
360 wxString
oldLabel(myHandler
->label
);
361 myHandler
->label
= shapeLabel
;
362 shapeLabel
= oldLabel
;
364 wxClientDC
dc(shape
->GetCanvas());
365 shape
->GetCanvas()->PrepareDC(dc
);
367 shape
->FormatText(dc
, (char*) (const char*) myHandler
->label
);
371 doc
->UpdateAllViews();
380 // Remove each individual line connected to a shape by sending a command.
381 void DiagramCommand::RemoveLines(wxShape
*shape
)
383 wxNode
*node
= shape
->GetLines().First();
386 wxLineShape
*line
= (wxLineShape
*)node
->Data();
387 doc
->GetCommandProcessor()->Submit(new DiagramCommand("Cut", OGLEDIT_CUT
, doc
, NULL
, 0.0, 0.0, line
->Selected(), line
));
389 node
= shape
->GetLines().First();
394 * MyEvtHandler: an event handler class for all shapes
397 void MyEvtHandler::OnLeftClick(double x
, double y
, int keys
, int attachment
)
399 wxClientDC
dc(GetShape()->GetCanvas());
400 GetShape()->GetCanvas()->PrepareDC(dc
);
404 // Selection is a concept the library knows about
405 if (GetShape()->Selected())
407 GetShape()->Select(FALSE
, &dc
);
408 GetShape()->GetCanvas()->Redraw(dc
); // Redraw because bits of objects will be are missing
412 // Ensure no other shape is selected, to simplify Undo/Redo code
414 wxNode
*node
= GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->First();
417 wxShape
*eachShape
= (wxShape
*)node
->Data();
418 if (eachShape
->GetParent() == NULL
)
420 if (eachShape
->Selected())
422 eachShape
->Select(FALSE
, &dc
);
428 GetShape()->Select(TRUE
, &dc
);
430 GetShape()->GetCanvas()->Redraw(dc
);
433 else if (keys
& KEY_CTRL
)
435 // Do something for CONTROL
439 wxGetApp().frame
->SetStatusText(label
);
444 * Implement connection of two shapes by right-dragging between them.
447 void MyEvtHandler::OnBeginDragRight(double x
, double y
, int keys
, int attachment
)
449 // Force attachment to be zero for now. Eventually we can deal with
450 // the actual attachment point, e.g. a rectangle side if attachment mode is on.
453 wxClientDC
dc(GetShape()->GetCanvas());
454 GetShape()->GetCanvas()->PrepareDC(dc
);
456 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
457 dc
.SetLogicalFunction(wxXOR
);
458 dc
.SetPen(dottedPen
);
460 GetShape()->GetAttachmentPosition(attachment
, &xp
, &yp
);
461 dc
.DrawLine(xp
, yp
, x
, y
);
462 GetShape()->GetCanvas()->CaptureMouse();
465 void MyEvtHandler::OnDragRight(bool draw
, double x
, double y
, int keys
, int attachment
)
467 // Force attachment to be zero for now
470 wxClientDC
dc(GetShape()->GetCanvas());
471 GetShape()->GetCanvas()->PrepareDC(dc
);
473 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
474 dc
.SetLogicalFunction(wxXOR
);
475 dc
.SetPen(dottedPen
);
477 GetShape()->GetAttachmentPosition(attachment
, &xp
, &yp
);
478 dc
.DrawLine(xp
, yp
, x
, y
);
481 void MyEvtHandler::OnEndDragRight(double x
, double y
, int keys
, int attachment
)
483 GetShape()->GetCanvas()->ReleaseMouse();
484 MyCanvas
*canvas
= (MyCanvas
*)GetShape()->GetCanvas();
486 // Check if we're on an object
488 wxShape
*otherShape
= canvas
->FindFirstSensitiveShape(x
, y
, &new_attachment
, OP_DRAG_RIGHT
);
490 if (otherShape
&& !otherShape
->IsKindOf(CLASSINFO(wxLineShape
)))
492 canvas
->view
->GetDocument()->GetCommandProcessor()->Submit(
493 new DiagramCommand("wxLineShape", OGLEDIT_ADD_LINE
, (DiagramDocument
*)canvas
->view
->GetDocument(), CLASSINFO(wxLineShape
),
494 0.0, 0.0, FALSE
, NULL
, GetShape(), otherShape
));
498 void MyEvtHandler::OnEndSize(double x
, double y
)
500 wxClientDC
dc(GetShape()->GetCanvas());
501 GetShape()->GetCanvas()->PrepareDC(dc
);
503 GetShape()->FormatText(dc
, (char*) (const char*) label
);
510 bool MyDiagram::OnShapeSave(wxExprDatabase
& db
, wxShape
& shape
, wxExpr
& expr
)
512 wxDiagram::OnShapeSave(db
, shape
, expr
);
513 MyEvtHandler
*handler
= (MyEvtHandler
*)shape
.GetEventHandler();
514 expr
.AddAttributeValueString("label", handler
->label
);
518 bool MyDiagram::OnShapeLoad(wxExprDatabase
& db
, wxShape
& shape
, wxExpr
& expr
)
520 wxDiagram::OnShapeLoad(db
, shape
, expr
);
522 expr
.AssignAttributeValue("label", &label
);
523 MyEvtHandler
*handler
= new MyEvtHandler(&shape
, &shape
, wxString(label
));
524 shape
.SetEventHandler(handler
);
535 IMPLEMENT_DYNAMIC_CLASS(wxRoundedRectangleShape
, wxRectangleShape
)
537 wxRoundedRectangleShape::wxRoundedRectangleShape(double w
, double h
):
538 wxRectangleShape(w
, h
)
540 // 0.3 of the smaller rectangle dimension
541 SetCornerRadius((double) -0.3);
544 IMPLEMENT_DYNAMIC_CLASS(wxDiamondShape
, wxPolygonShape
)
546 wxDiamondShape::wxDiamondShape(double w
, double h
):
549 // wxPolygonShape::SetSize relies on the shape having non-zero
556 wxList
*thePoints
= new wxList
;
557 wxRealPoint
*point
= new wxRealPoint(0.0, (-h
/2.0));
558 thePoints
->Append((wxObject
*) point
);
560 point
= new wxRealPoint((w
/2.0), 0.0);
561 thePoints
->Append((wxObject
*) point
);
563 point
= new wxRealPoint(0.0, (h
/2.0));
564 thePoints
->Append((wxObject
*) point
);
566 point
= new wxRealPoint((-w
/2.0), 0.0);
567 thePoints
->Append((wxObject
*) point
);