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