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