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