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