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