]> git.saurik.com Git - wxWidgets.git/blob - contrib/samples/ogl/ogledit/doc.cpp
Assert correction.
[wxWidgets.git] / contrib / samples / ogl / ogledit / doc.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: doc.cpp
3 // Purpose: Implements document functionality in OGLEdit
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 12/07/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 // #pragma implementation
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include <wx/wx.h>
25 #endif
26
27 #include <wx/ioswrap.h>
28
29 #if !wxUSE_DOC_VIEW_ARCHITECTURE
30 #error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in wx_setup.h!
31 #endif
32
33 #include "ogledit.h"
34 #include "doc.h"
35 #include "view.h"
36
37 IMPLEMENT_DYNAMIC_CLASS(DiagramDocument, wxDocument)
38
39 DiagramDocument::DiagramDocument(void)
40 {
41 }
42
43 DiagramDocument::~DiagramDocument(void)
44 {
45 }
46
47 bool DiagramDocument::OnCloseDocument(void)
48 {
49 diagram.DeleteAllShapes();
50 return true;
51 }
52
53 #if wxUSE_STD_IOSTREAM
54 wxSTD ostream& DiagramDocument::SaveObject(wxSTD ostream& stream)
55 {
56 #if wxUSE_PROLOGIO
57
58 wxDocument::SaveObject(stream);
59
60 char buf[400];
61 (void) wxGetTempFileName("diag", buf);
62
63 diagram.SaveFile(buf);
64 wxTransferFileToStream(buf, stream);
65
66 wxRemoveFile(buf);
67
68 #endif
69
70 return stream;
71 }
72
73 wxSTD istream& DiagramDocument::LoadObject(wxSTD istream& stream)
74 {
75 #if wxUSE_PROLOGIO
76
77 wxDocument::LoadObject(stream);
78
79 char buf[400];
80 (void) wxGetTempFileName("diag", buf);
81
82 wxTransferStreamToFile(stream, buf);
83
84 diagram.DeleteAllShapes();
85 diagram.LoadFile(buf);
86 wxRemoveFile(buf);
87
88 #endif
89
90 return stream;
91 }
92 #else
93
94 wxOutputStream& DiagramDocument::SaveObject(wxOutputStream& stream)
95 {
96 #if wxUSE_PROLOGIO
97
98 wxDocument::SaveObject(stream);
99 wxChar buf[400];
100 (void) wxGetTempFileName(_T("diag"), buf);
101
102 diagram.SaveFile(buf);
103
104 wxTransferFileToStream(buf, stream);
105
106 wxRemoveFile(buf);
107
108 #endif
109
110 return stream;
111 }
112
113 wxInputStream& DiagramDocument::LoadObject(wxInputStream& stream)
114 {
115 #if wxUSE_PROLOGIO
116 wxDocument::LoadObject(stream);
117
118 wxChar buf[400];
119 (void) wxGetTempFileName(_T("diag"), buf);
120
121 wxTransferStreamToFile(stream, buf);
122
123 diagram.DeleteAllShapes();
124 diagram.LoadFile(buf);
125 wxRemoveFile(buf);
126 #endif
127
128 return stream;
129 }
130
131 #endif
132
133 /*
134 * Implementation of drawing command
135 */
136
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)
140 {
141 doc = ddoc;
142 cmd = command;
143 shape = theShape;
144 fromShape = fs;
145 toShape = ts;
146 shapeInfo = info;
147 shapeBrush = NULL;
148 shapePen = NULL;
149 x = xx;
150 y = yy;
151 selected = sel;
152 deleteShape = false;
153 }
154
155 DiagramCommand::DiagramCommand(const wxString& name, int command, DiagramDocument *ddoc, wxBrush *backgroundColour, wxShape *theShape)
156 :wxCommand(true, name)
157 {
158 doc = ddoc;
159 cmd = command;
160 shape = theShape;
161 fromShape = NULL;
162 toShape = NULL;
163 shapeInfo = NULL;
164 x = 0.0;
165 y = 0.0;
166 selected = false;
167 deleteShape = false;
168 shapeBrush = backgroundColour;
169 shapePen = NULL;
170 }
171
172 DiagramCommand::DiagramCommand(const wxString& name, int command, DiagramDocument *ddoc, const wxString& lab, wxShape *theShape)
173 :wxCommand(true, name)
174 {
175 doc = ddoc;
176 cmd = command;
177 shape = theShape;
178 fromShape = NULL;
179 toShape = NULL;
180 shapeInfo = NULL;
181 x = 0.0;
182 y = 0.0;
183 selected = false;
184 deleteShape = false;
185 shapeBrush = NULL;
186 shapePen = NULL;
187 shapeLabel = lab;
188 }
189
190 DiagramCommand::~DiagramCommand(void)
191 {
192 if (shape && deleteShape)
193 {
194 shape->SetCanvas(NULL);
195 delete shape;
196 }
197 }
198
199 bool DiagramCommand::Do(void)
200 {
201 switch (cmd)
202 {
203 case wxID_CUT:
204 {
205 if (shape)
206 {
207 deleteShape = true;
208
209 shape->Select(false);
210
211 // Generate commands to explicitly remove each connected line.
212 RemoveLines(shape);
213
214 doc->GetDiagram()->RemoveShape(shape);
215 if (shape->IsKindOf(CLASSINFO(wxLineShape)))
216 {
217 wxLineShape *lineShape = (wxLineShape *)shape;
218 fromShape = lineShape->GetFrom();
219 toShape = lineShape->GetTo();
220 }
221 shape->Unlink();
222
223 doc->Modify(true);
224 doc->UpdateAllViews();
225 }
226
227 break;
228 }
229 case OGLEDIT_ADD_SHAPE:
230 {
231 wxShape *theShape;
232 if (shape)
233 theShape = shape; // Saved from undoing the shape
234 else
235 {
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);
242
243 theShape->SetSize(60, 60);
244 }
245 doc->GetDiagram()->AddShape(theShape);
246 theShape->Show(true);
247
248 wxClientDC dc(theShape->GetCanvas());
249 theShape->GetCanvas()->PrepareDC(dc);
250
251 theShape->Move(dc, x, y);
252
253 shape = theShape;
254 deleteShape = false;
255
256 doc->Modify(true);
257 doc->UpdateAllViews();
258 break;
259 }
260 case OGLEDIT_ADD_LINE:
261 {
262 wxShape *theShape;
263 if (shape)
264 theShape = shape; // Saved from undoing the line
265 else
266 {
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);
272
273 wxLineShape *lineShape = (wxLineShape *)theShape;
274
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"));
279 }
280
281 doc->GetDiagram()->AddShape(theShape);
282
283 fromShape->AddLine((wxLineShape *)theShape, toShape);
284
285 theShape->Show(true);
286
287 wxClientDC dc(theShape->GetCanvas());
288 theShape->GetCanvas()->PrepareDC(dc);
289
290 // It won't get drawn properly unless you move both
291 // connected images
292 fromShape->Move(dc, fromShape->GetX(), fromShape->GetY());
293 toShape->Move(dc, toShape->GetX(), toShape->GetY());
294
295 shape = theShape;
296 deleteShape = false;
297
298 doc->Modify(true);
299 doc->UpdateAllViews();
300 break;
301 }
302 case OGLEDIT_CHANGE_BACKGROUND_COLOUR:
303 {
304 if (shape)
305 {
306 wxClientDC dc(shape->GetCanvas());
307 shape->GetCanvas()->PrepareDC(dc);
308
309 wxBrush *oldBrush = shape->GetBrush();
310 shape->SetBrush(shapeBrush);
311 shapeBrush = oldBrush;
312 shape->Draw(dc);
313
314 doc->Modify(true);
315 doc->UpdateAllViews();
316 }
317
318 break;
319 }
320 case OGLEDIT_EDIT_LABEL:
321 {
322 if (shape)
323 {
324 MyEvtHandler *myHandler = (MyEvtHandler *)shape->GetEventHandler();
325 wxString oldLabel(myHandler->label);
326 myHandler->label = shapeLabel;
327 shapeLabel = oldLabel;
328
329 wxClientDC dc(shape->GetCanvas());
330 shape->GetCanvas()->PrepareDC(dc);
331
332 shape->FormatText(dc, /* (char*) (const char*) */ myHandler->label);
333 shape->Draw(dc);
334
335 doc->Modify(true);
336 doc->UpdateAllViews();
337 }
338
339 break;
340 }
341 }
342 return true;
343 }
344
345 bool DiagramCommand::Undo(void)
346 {
347 switch (cmd)
348 {
349 case wxID_CUT:
350 {
351 if (shape)
352 {
353 doc->GetDiagram()->AddShape(shape);
354 shape->Show(true);
355
356 if (shape->IsKindOf(CLASSINFO(wxLineShape)))
357 {
358 wxLineShape *lineShape = (wxLineShape *)shape;
359
360 fromShape->AddLine(lineShape, toShape);
361 }
362 if (selected)
363 shape->Select(true);
364
365 deleteShape = false;
366 }
367 doc->Modify(true);
368 doc->UpdateAllViews();
369 break;
370 }
371 case OGLEDIT_ADD_SHAPE:
372 case OGLEDIT_ADD_LINE:
373 {
374 if (shape)
375 {
376 wxClientDC dc(shape->GetCanvas());
377 shape->GetCanvas()->PrepareDC(dc);
378
379 shape->Select(false, &dc);
380 doc->GetDiagram()->RemoveShape(shape);
381 shape->Unlink();
382 deleteShape = true;
383 }
384 doc->Modify(true);
385 doc->UpdateAllViews();
386 break;
387 }
388 case OGLEDIT_CHANGE_BACKGROUND_COLOUR:
389 {
390 if (shape)
391 {
392 wxClientDC dc(shape->GetCanvas());
393 shape->GetCanvas()->PrepareDC(dc);
394
395 wxBrush *oldBrush = shape->GetBrush();
396 shape->SetBrush(shapeBrush);
397 shapeBrush = oldBrush;
398 shape->Draw(dc);
399
400 doc->Modify(true);
401 doc->UpdateAllViews();
402 }
403 break;
404 }
405 case OGLEDIT_EDIT_LABEL:
406 {
407 if (shape)
408 {
409 MyEvtHandler *myHandler = (MyEvtHandler *)shape->GetEventHandler();
410 wxString oldLabel(myHandler->label);
411 myHandler->label = shapeLabel;
412 shapeLabel = oldLabel;
413
414 wxClientDC dc(shape->GetCanvas());
415 shape->GetCanvas()->PrepareDC(dc);
416
417 shape->FormatText(dc, /* (char*) (const char*) */ myHandler->label);
418 shape->Draw(dc);
419
420 doc->Modify(true);
421 doc->UpdateAllViews();
422 }
423
424 break;
425 }
426 }
427 return true;
428 }
429
430 // Remove each individual line connected to a shape by sending a command.
431 void DiagramCommand::RemoveLines(wxShape *shape)
432 {
433 wxObjectList::compatibility_iterator node = shape->GetLines().GetFirst();
434 while (node)
435 {
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));
438
439 node = shape->GetLines().GetFirst();
440 }
441 }
442
443 /*
444 * MyEvtHandler: an event handler class for all shapes
445 */
446
447 void MyEvtHandler::OnLeftClick(double WXUNUSED(x), double WXUNUSED(y), int keys, int WXUNUSED(attachment))
448 {
449 wxClientDC dc(GetShape()->GetCanvas());
450 GetShape()->GetCanvas()->PrepareDC(dc);
451
452 if (keys == 0)
453 {
454 // Selection is a concept the library knows about
455 if (GetShape()->Selected())
456 {
457 GetShape()->Select(false, &dc);
458 GetShape()->GetCanvas()->Redraw(dc); // Redraw because bits of objects will be are missing
459 }
460 else
461 {
462 // Ensure no other shape is selected, to simplify Undo/Redo code
463 bool redraw = false;
464 wxObjectList::compatibility_iterator node = GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->GetFirst();
465 while (node)
466 {
467 wxShape *eachShape = (wxShape *)node->GetData();
468 if (eachShape->GetParent() == NULL)
469 {
470 if (eachShape->Selected())
471 {
472 eachShape->Select(false, &dc);
473 redraw = true;
474 }
475 }
476 node = node->GetNext();
477 }
478 GetShape()->Select(true, &dc);
479 if (redraw)
480 GetShape()->GetCanvas()->Redraw(dc);
481 }
482 }
483 else if (keys & KEY_CTRL)
484 {
485 // Do something for CONTROL
486 }
487 else
488 {
489 #if wxUSE_STATUSBAR
490 wxGetApp().frame->SetStatusText(label);
491 #endif // wxUSE_STATUSBAR
492 }
493 }
494
495 /*
496 * Implement connection of two shapes by right-dragging between them.
497 */
498
499 void MyEvtHandler::OnBeginDragRight(double x, double y, int WXUNUSED(keys), int attachment)
500 {
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.
503 attachment = 0;
504
505 wxClientDC dc(GetShape()->GetCanvas());
506 GetShape()->GetCanvas()->PrepareDC(dc);
507
508 wxPen dottedPen(*wxBLACK, 1, wxDOT);
509 dc.SetLogicalFunction(OGLRBLF);
510 dc.SetPen(dottedPen);
511 double xp, yp;
512 GetShape()->GetAttachmentPosition(attachment, &xp, &yp);
513 dc.DrawLine((long) xp, (long) yp, (long) x, (long) y);
514 GetShape()->GetCanvas()->CaptureMouse();
515 }
516
517 void MyEvtHandler::OnDragRight(bool WXUNUSED(draw), double x, double y, int WXUNUSED(keys), int attachment)
518 {
519 // Force attachment to be zero for now
520 attachment = 0;
521
522 wxClientDC dc(GetShape()->GetCanvas());
523 GetShape()->GetCanvas()->PrepareDC(dc);
524
525 wxPen dottedPen(*wxBLACK, 1, wxDOT);
526 dc.SetLogicalFunction(OGLRBLF);
527 dc.SetPen(dottedPen);
528 double xp, yp;
529 GetShape()->GetAttachmentPosition(attachment, &xp, &yp);
530 dc.DrawLine((long) xp, (long) yp, (long) x, (long) y);
531 }
532
533 void MyEvtHandler::OnEndDragRight(double x, double y, int WXUNUSED(keys), int WXUNUSED(attachment))
534 {
535 GetShape()->GetCanvas()->ReleaseMouse();
536 MyCanvas *canvas = (MyCanvas *)GetShape()->GetCanvas();
537
538 // Check if we're on an object
539 int new_attachment;
540 wxShape *otherShape = canvas->FindFirstSensitiveShape(x, y, &new_attachment, OP_DRAG_RIGHT);
541
542 if (otherShape && !otherShape->IsKindOf(CLASSINFO(wxLineShape)))
543 {
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));
547 }
548 }
549
550 void MyEvtHandler::OnEndSize(double WXUNUSED(x), double WXUNUSED(y))
551 {
552 wxClientDC dc(GetShape()->GetCanvas());
553 GetShape()->GetCanvas()->PrepareDC(dc);
554
555 GetShape()->FormatText(dc, /* (char*) (const char*) */ label);
556 }
557
558 /*
559 * Diagram
560 */
561
562 #if wxUSE_PROLOGIO
563
564 bool MyDiagram::OnShapeSave(wxExprDatabase& db, wxShape& shape, wxExpr& expr)
565 {
566 wxDiagram::OnShapeSave(db, shape, expr);
567 MyEvtHandler *handler = (MyEvtHandler *)shape.GetEventHandler();
568 expr.AddAttributeValueString(_T("label"), handler->label);
569 return true;
570 }
571
572 bool MyDiagram::OnShapeLoad(wxExprDatabase& db, wxShape& shape, wxExpr& expr)
573 {
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);
579
580 if (label)
581 delete[] label;
582 return true;
583 }
584
585 #endif
586
587 /*
588 * New shapes
589 */
590
591 IMPLEMENT_DYNAMIC_CLASS(wxRoundedRectangleShape, wxRectangleShape)
592
593 wxRoundedRectangleShape::wxRoundedRectangleShape(double w, double h):
594 wxRectangleShape(w, h)
595 {
596 // 0.3 of the smaller rectangle dimension
597 SetCornerRadius((double) -0.3);
598 }
599
600 IMPLEMENT_DYNAMIC_CLASS(wxDiamondShape, wxPolygonShape)
601
602 wxDiamondShape::wxDiamondShape(double w, double h):
603 wxPolygonShape()
604 {
605 // wxPolygonShape::SetSize relies on the shape having non-zero
606 // size initially.
607 if (w == 0.0)
608 w = 60.0;
609 if (h == 0.0)
610 h = 60.0;
611
612 wxList *thePoints = new wxList;
613 wxRealPoint *point = new wxRealPoint(0.0, (-h/2.0));
614 thePoints->Append((wxObject*) point);
615
616 point = new wxRealPoint((w/2.0), 0.0);
617 thePoints->Append((wxObject*) point);
618
619 point = new wxRealPoint(0.0, (h/2.0));
620 thePoints->Append((wxObject*) point);
621
622 point = new wxRealPoint((-w/2.0), 0.0);
623 thePoints->Append((wxObject*) point);
624
625 Create(thePoints);
626 }