]> git.saurik.com Git - wxWidgets.git/blame - contrib/samples/ogl/studio/doc.cpp
Elliptic arc fix for getting bounds
[wxWidgets.git] / contrib / samples / ogl / studio / doc.cpp
CommitLineData
1fc25a89
JS
1/////////////////////////////////////////////////////////////////////////////
2// Name: doc.cpp
3// Purpose: Implements document functionality
4// Author: Julian Smart
5// Modified by:
6// Created: 12/07/98
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart
2ba06d5a 9// Licence: wxWindows licence
1fc25a89
JS
10/////////////////////////////////////////////////////////////////////////////
11
12#ifdef __GNUG__
13// #pragma implementation
14#endif
15
16// For compilers that support precompilation, includes "wx.h".
92a19c2e 17#include "wx/wxprec.h"
1fc25a89
JS
18
19#ifdef __BORLANDC__
20#pragma hdrstop
21#endif
22
23#ifndef WX_PRECOMP
24#include <wx/wx.h>
25#endif
26
1fc25a89
JS
27#include "studio.h"
28#include "doc.h"
29#include "view.h"
30#include <wx/ogl/basicp.h>
31
32IMPLEMENT_DYNAMIC_CLASS(csDiagramDocument, wxDocument)
33
2b5dcd17 34#ifdef __VISUALC__
1fc25a89
JS
35#pragma warning(disable:4355)
36#endif
37
38csDiagramDocument::csDiagramDocument():m_diagram(this)
39{
40}
41
2b5dcd17 42#ifdef __VISUALC__
1fc25a89
JS
43#pragma warning(default:4355)
44#endif
45
46csDiagramDocument::~csDiagramDocument()
47{
48}
49
50bool csDiagramDocument::OnCloseDocument()
51{
52 m_diagram.DeleteAllShapes();
2ba06d5a 53 return true;
1fc25a89
JS
54}
55
56bool csDiagramDocument::OnSaveDocument(const wxString& file)
57{
1484b5cc 58 if (file == wxEmptyString)
2ba06d5a 59 return false;
1fc25a89
JS
60
61 if (!m_diagram.SaveFile(file))
62 {
63 wxString msgTitle;
1484b5cc 64 if (wxTheApp->GetAppName() != wxEmptyString)
1fc25a89
JS
65 msgTitle = wxTheApp->GetAppName();
66 else
1484b5cc 67 msgTitle = wxString(_T("File error"));
1fc25a89 68
1484b5cc 69 (void)wxMessageBox(_T("Sorry, could not open this file for saving."), msgTitle, wxOK | wxICON_EXCLAMATION,
1fc25a89 70 GetDocumentWindow());
2ba06d5a 71 return false;
1fc25a89
JS
72 }
73
2ba06d5a 74 Modify(false);
1fc25a89 75 SetFilename(file);
2ba06d5a 76 return true;
1fc25a89 77}
2ba06d5a 78
1fc25a89
JS
79bool csDiagramDocument::OnOpenDocument(const wxString& file)
80{
81 if (!OnSaveModified())
2ba06d5a 82 return false;
1fc25a89
JS
83
84 wxString msgTitle;
1484b5cc 85 if (wxTheApp->GetAppName() != wxEmptyString)
1fc25a89
JS
86 msgTitle = wxTheApp->GetAppName();
87 else
1484b5cc 88 msgTitle = wxString(_T("File error"));
1fc25a89
JS
89
90 m_diagram.DeleteAllShapes();
91 if (!m_diagram.LoadFile(file))
92 {
1484b5cc 93 (void)wxMessageBox(_T("Sorry, could not open this file."), msgTitle, wxOK|wxICON_EXCLAMATION,
1fc25a89 94 GetDocumentWindow());
2ba06d5a 95 return false;
1fc25a89 96 }
2ba06d5a
WS
97 SetFilename(file, true);
98 Modify(false);
1fc25a89
JS
99 UpdateAllViews();
100
2ba06d5a 101 return true;
1fc25a89 102}
2ba06d5a 103
1fc25a89
JS
104
105/*
106 * Implementation of drawing command
107 */
108
109csDiagramCommand::csDiagramCommand(const wxString& name, csDiagramDocument *doc,
110 csCommandState* onlyState):
2ba06d5a 111 wxCommand(true, name)
1fc25a89
JS
112{
113 m_doc = doc;
114
115 if (onlyState)
116 {
117 AddState(onlyState);
118 }
119}
120
121csDiagramCommand::~csDiagramCommand()
122{
36ca94a2 123 wxObjectList::compatibility_iterator node = m_states.GetFirst();
1fc25a89
JS
124 while (node)
125 {
8552e6f0 126 csCommandState* state = (csCommandState*) node->GetData();
1fc25a89 127 delete state;
8552e6f0 128 node = node->GetNext();
1fc25a89
JS
129 }
130}
131
132void csDiagramCommand::AddState(csCommandState* state)
133{
134 state->m_doc = m_doc;
135// state->m_cmd = m_cmd;
136 m_states.Append(state);
137}
138
139// Insert a state at the beginning of the list
140void csDiagramCommand::InsertState(csCommandState* state)
141{
142 state->m_doc = m_doc;
143// state->m_cmd = m_cmd;
144 m_states.Insert(state);
145}
146
147// Schedule all lines connected to the states to be cut.
148void csDiagramCommand::RemoveLines()
149{
36ca94a2 150 wxObjectList::compatibility_iterator node = m_states.GetFirst();
1fc25a89
JS
151 while (node)
152 {
8552e6f0 153 csCommandState* state = (csCommandState*) node->GetData();
1fc25a89
JS
154 wxShape* shape = state->GetShapeOnCanvas();
155 wxASSERT( (shape != NULL) );
156
36ca94a2 157 wxObjectList::compatibility_iterator node1 = shape->GetLines().GetFirst();
1fc25a89
JS
158 while (node1)
159 {
8552e6f0 160 wxLineShape *line = (wxLineShape *)node1->GetData();
1fc25a89
JS
161 if (!FindStateByShape(line))
162 {
163 csCommandState* newState = new csCommandState(ID_CS_CUT, NULL, line);
164 InsertState(newState);
165 }
166
8552e6f0 167 node1 = node1->GetNext();
1fc25a89 168 }
8552e6f0 169 node = node->GetNext();
1fc25a89
JS
170 }
171}
172
173csCommandState* csDiagramCommand::FindStateByShape(wxShape* shape)
174{
36ca94a2 175 wxObjectList::compatibility_iterator node = m_states.GetFirst();
1fc25a89
JS
176 while (node)
177 {
8552e6f0 178 csCommandState* state = (csCommandState*) node->GetData();
1fc25a89
JS
179 if (shape == state->GetShapeOnCanvas() || shape == state->GetSavedState())
180 return state;
8552e6f0 181 node = node->GetNext();
1fc25a89
JS
182 }
183 return NULL;
184}
185
186bool csDiagramCommand::Do()
187{
36ca94a2 188 wxObjectList::compatibility_iterator node = m_states.GetFirst();
1fc25a89
JS
189 while (node)
190 {
8552e6f0 191 csCommandState* state = (csCommandState*) node->GetData();
1fc25a89 192 if (!state->Do())
2ba06d5a 193 return false;
8552e6f0 194 node = node->GetNext();
1fc25a89 195 }
2ba06d5a 196 return true;
1fc25a89
JS
197}
198
199bool csDiagramCommand::Undo()
200{
201 // Undo in reverse order, so e.g. shapes get added
202 // back before the lines do.
36ca94a2 203 wxObjectList::compatibility_iterator node = m_states.GetLast();
1fc25a89
JS
204 while (node)
205 {
8552e6f0 206 csCommandState* state = (csCommandState*) node->GetData();
1fc25a89 207 if (!state->Undo())
2ba06d5a 208 return false;
8552e6f0 209 node = node->GetPrevious();
1fc25a89 210 }
2ba06d5a 211 return true;
1fc25a89
JS
212}
213
214csCommandState::csCommandState(int cmd, wxShape* savedState, wxShape* shapeOnCanvas)
215{
216 m_cmd = cmd;
217 m_doc = NULL;
218 m_savedState = savedState;
219 m_shapeOnCanvas = shapeOnCanvas;
220 m_linePositionFrom = 0;
221 m_linePositionTo = 0;
222}
223
224csCommandState::~csCommandState()
225{
226 if (m_savedState)
227 {
228 m_savedState->SetCanvas(NULL);
229 delete m_savedState;
230 }
231}
232
233bool csCommandState::Do()
234{
235 switch (m_cmd)
236 {
237 case ID_CS_CUT:
238 {
239 // New state is 'nothing' - maybe pass shape ID to state so we know what
240 // we're talking about.
241 // Then save old shape in m_savedState (actually swap pointers)
242
243 wxASSERT( (m_shapeOnCanvas != NULL) );
244 wxASSERT( (m_savedState == NULL) ); // new state will be 'nothing'
245 wxASSERT( (m_doc != NULL) );
246
247 wxShapeCanvas* canvas = m_shapeOnCanvas->GetCanvas();
248
249 // In case this is a line
250 wxShape* lineFrom = NULL;
251 wxShape* lineTo = NULL;
252 int attachmentFrom = 0, attachmentTo = 0;
253
254 if (m_shapeOnCanvas->IsKindOf(CLASSINFO(wxLineShape)))
255 {
256 // Store the from/to info to save in the line shape
257 wxLineShape* lineShape = (wxLineShape*) m_shapeOnCanvas;
258 lineFrom = lineShape->GetFrom();
259 lineTo = lineShape->GetTo();
260 attachmentFrom = lineShape->GetAttachmentFrom();
261 attachmentTo = lineShape->GetAttachmentTo();
262
263 m_linePositionFrom = lineFrom->GetLinePosition(lineShape);
264 m_linePositionTo = lineTo->GetLinePosition(lineShape);
265 }
266
2ba06d5a
WS
267 m_shapeOnCanvas->Select(false);
268 ((csDiagramView*) m_doc->GetFirstView())->SelectShape(m_shapeOnCanvas, false);
1fc25a89
JS
269
270 m_shapeOnCanvas->Unlink();
271
272 m_doc->GetDiagram()->RemoveShape(m_shapeOnCanvas);
273
274 m_savedState = m_shapeOnCanvas;
275
276 if (m_savedState->IsKindOf(CLASSINFO(wxLineShape)))
277 {
278 // Restore the from/to info for future reference
279 wxLineShape* lineShape = (wxLineShape*) m_savedState;
280 lineShape->SetFrom(lineFrom);
281 lineShape->SetTo(lineTo);
282 lineShape->SetAttachments(attachmentFrom, attachmentTo);
283
284 wxClientDC dc(canvas);
285 canvas->PrepareDC(dc);
286
287 lineFrom->MoveLinks(dc);
288 lineTo->MoveLinks(dc);
289 }
290
2ba06d5a 291 m_doc->Modify(true);
1fc25a89
JS
292 m_doc->UpdateAllViews();
293 break;
294 }
295 case ID_CS_ADD_SHAPE:
296 case ID_CS_ADD_SHAPE_SELECT:
297 {
298 // The app has given the command state a new m_savedState
299 // shape, which is the new shape to add to the canvas (but
300 // not actually added until this point).
301 // The new 'saved state' is therefore 'nothing' since there
302 // was nothing there before.
303
304 wxASSERT( (m_shapeOnCanvas == NULL) );
305 wxASSERT( (m_savedState != NULL) );
306 wxASSERT( (m_doc != NULL) );
307
308 m_shapeOnCanvas = m_savedState;
309 m_savedState = NULL;
310
311 m_doc->GetDiagram()->AddShape(m_shapeOnCanvas);
2ba06d5a 312 m_shapeOnCanvas->Show(true);
1fc25a89
JS
313
314 wxClientDC dc(m_shapeOnCanvas->GetCanvas());
315 m_shapeOnCanvas->GetCanvas()->PrepareDC(dc);
316
317 csEvtHandler *handler = (csEvtHandler *)m_shapeOnCanvas->GetEventHandler();
318 m_shapeOnCanvas->FormatText(dc, handler->m_label);
319
320 m_shapeOnCanvas->Move(dc, m_shapeOnCanvas->GetX(), m_shapeOnCanvas->GetY());
321
322 if (m_cmd == ID_CS_ADD_SHAPE_SELECT)
323 {
2ba06d5a
WS
324 m_shapeOnCanvas->Select(true, &dc);
325 ((csDiagramView*) m_doc->GetFirstView())->SelectShape(m_shapeOnCanvas, true);
1fc25a89
JS
326 }
327
2ba06d5a 328 m_doc->Modify(true);
1fc25a89
JS
329 m_doc->UpdateAllViews();
330 break;
331 }
332 case ID_CS_ADD_LINE:
333 case ID_CS_ADD_LINE_SELECT:
334 {
335 wxASSERT( (m_shapeOnCanvas == NULL) );
336 wxASSERT( (m_savedState != NULL) );
337 wxASSERT( (m_doc != NULL) );
338
339 wxLineShape *lineShape = (wxLineShape *)m_savedState;
340 wxASSERT( (lineShape->GetFrom() != NULL) );
341 wxASSERT( (lineShape->GetTo() != NULL) );
342
343 m_shapeOnCanvas = m_savedState;
344 m_savedState = NULL;
345
346 m_doc->GetDiagram()->AddShape(lineShape);
347
348 lineShape->GetFrom()->AddLine(lineShape, lineShape->GetTo(),
349 lineShape->GetAttachmentFrom(), lineShape->GetAttachmentTo());
350
2ba06d5a 351 lineShape->Show(true);
1fc25a89
JS
352
353 wxClientDC dc(lineShape->GetCanvas());
354 lineShape->GetCanvas()->PrepareDC(dc);
355
356 // It won't get drawn properly unless you move both
357 // connected images
358 lineShape->GetFrom()->Move(dc, lineShape->GetFrom()->GetX(), lineShape->GetFrom()->GetY());
359 lineShape->GetTo()->Move(dc, lineShape->GetTo()->GetX(), lineShape->GetTo()->GetY());
360
361 if (m_cmd == ID_CS_ADD_LINE_SELECT)
362 {
2ba06d5a
WS
363 lineShape->Select(true, &dc);
364 ((csDiagramView*) m_doc->GetFirstView())->SelectShape(m_shapeOnCanvas, true);
1fc25a89
JS
365 }
366
2ba06d5a 367 m_doc->Modify(true);
1fc25a89
JS
368 m_doc->UpdateAllViews();
369 break;
370 }
371 case ID_CS_CHANGE_BACKGROUND_COLOUR:
372 case ID_CS_MOVE:
373 case ID_CS_SIZE:
374 case ID_CS_EDIT_PROPERTIES:
375 case ID_CS_FONT_CHANGE:
376 case ID_CS_ARROW_CHANGE:
377 case ID_CS_ROTATE_CLOCKWISE:
378 case ID_CS_ROTATE_ANTICLOCKWISE:
379 case ID_CS_CHANGE_LINE_ORDERING:
380 case ID_CS_CHANGE_LINE_ATTACHMENT:
381 case ID_CS_ALIGN:
382 case ID_CS_NEW_POINT:
383 case ID_CS_CUT_POINT:
384 case ID_CS_MOVE_LINE_POINT:
385 case ID_CS_STRAIGHTEN:
386 case ID_CS_MOVE_LABEL:
387 {
388 // At this point we have been given a new shape
389 // just like the old one but with a changed colour.
390 // It's now time to apply that change to the
391 // shape on the canvas, saving the old state.
392 // NOTE: this is general enough to work with MOST attribute
393 // changes!
394
395 wxASSERT( (m_shapeOnCanvas != NULL) );
396 wxASSERT( (m_savedState != NULL) ); // This is the new shape with changed colour
397 wxASSERT( (m_doc != NULL) );
398
399 wxClientDC dc(m_shapeOnCanvas->GetCanvas());
400 m_shapeOnCanvas->GetCanvas()->PrepareDC(dc);
401
402 bool isSelected = m_shapeOnCanvas->Selected();
403 if (isSelected)
2ba06d5a 404 m_shapeOnCanvas->Select(false, & dc);
1fc25a89
JS
405
406 if (m_cmd == ID_CS_SIZE || m_cmd == ID_CS_ROTATE_CLOCKWISE || m_cmd == ID_CS_ROTATE_ANTICLOCKWISE ||
407 m_cmd == ID_CS_CHANGE_LINE_ORDERING || m_cmd == ID_CS_CHANGE_LINE_ATTACHMENT)
408 {
409 m_shapeOnCanvas->Erase(dc);
410 }
411
412 // TODO: make sure the ID is the same. Or, when applying the new state,
413 // don't change the original ID.
414 wxShape* tempShape = m_shapeOnCanvas->CreateNewCopy();
415
416 // Apply the saved state to the shape on the canvas, by copying.
417 m_savedState->CopyWithHandler(*m_shapeOnCanvas);
418
419 // Delete this state now it's been used (m_shapeOnCanvas currently holds this state)
420 delete m_savedState;
421
422 // Remember the previous state
423 m_savedState = tempShape;
424
425 // Redraw the shape
426
427 if (m_cmd == ID_CS_MOVE || m_cmd == ID_CS_ROTATE_CLOCKWISE || m_cmd == ID_CS_ROTATE_ANTICLOCKWISE ||
428 m_cmd == ID_CS_ALIGN)
429 {
430 m_shapeOnCanvas->Move(dc, m_shapeOnCanvas->GetX(), m_shapeOnCanvas->GetY());
431
432 csEvtHandler *handler = (csEvtHandler *)m_shapeOnCanvas->GetEventHandler();
433 m_shapeOnCanvas->FormatText(dc, handler->m_label);
434 m_shapeOnCanvas->Draw(dc);
435 }
436 else if (m_cmd == ID_CS_CHANGE_LINE_ORDERING)
437 {
438 m_shapeOnCanvas->MoveLinks(dc);
439 }
440 else if (m_cmd == ID_CS_CHANGE_LINE_ATTACHMENT)
441 {
442 wxLineShape *lineShape = (wxLineShape *)m_shapeOnCanvas;
443
444 // Have to move both sets of links since we don't know which links
445 // have been affected (unless we compared before and after states).
446 lineShape->GetFrom()->MoveLinks(dc);
447 lineShape->GetTo()->MoveLinks(dc);
448 }
449 else if (m_cmd == ID_CS_SIZE)
450 {
451 double width, height;
452 m_shapeOnCanvas->GetBoundingBoxMax(&width, &height);
453
454 m_shapeOnCanvas->SetSize(width, height);
455 m_shapeOnCanvas->Move(dc, m_shapeOnCanvas->GetX(), m_shapeOnCanvas->GetY());
456
2ba06d5a 457 m_shapeOnCanvas->Show(true);
1fc25a89
JS
458
459 // Recursively redraw links if we have a composite.
8552e6f0 460 if (m_shapeOnCanvas->GetChildren().GetCount() > 0)
2ba06d5a 461 m_shapeOnCanvas->DrawLinks(dc, -1, true);
1fc25a89
JS
462
463 m_shapeOnCanvas->GetEventHandler()->OnEndSize(width, height);
464 }
465 else if (m_cmd == ID_CS_EDIT_PROPERTIES || m_cmd == ID_CS_FONT_CHANGE)
466 {
467 csEvtHandler *handler = (csEvtHandler *)m_shapeOnCanvas->GetEventHandler();
468 m_shapeOnCanvas->FormatText(dc, handler->m_label);
469 m_shapeOnCanvas->Draw(dc);
470 }
471 else
472 {
473 m_shapeOnCanvas->Draw(dc);
474 }
475
476 if (isSelected)
2ba06d5a 477 m_shapeOnCanvas->Select(true, & dc);
1fc25a89 478
2ba06d5a 479 m_doc->Modify(true);
1fc25a89
JS
480 m_doc->UpdateAllViews();
481
482 break;
483 }
484 }
2ba06d5a 485 return true;
1fc25a89
JS
486}
487
488bool csCommandState::Undo()
489{
490 switch (m_cmd)
491 {
492 case ID_CS_CUT:
493 {
494 wxASSERT( (m_savedState != NULL) );
495 wxASSERT( (m_doc != NULL) );
496
497 m_doc->GetDiagram()->AddShape(m_savedState);
498 m_shapeOnCanvas = m_savedState;
499 m_savedState = NULL;
500
501 if (m_shapeOnCanvas->IsKindOf(CLASSINFO(wxLineShape)))
502 {
503 wxLineShape* lineShape = (wxLineShape*) m_shapeOnCanvas;
504 lineShape->GetFrom()->AddLine(lineShape, lineShape->GetTo(),
505 lineShape->GetAttachmentFrom(), lineShape->GetAttachmentTo(),
506 m_linePositionFrom, m_linePositionTo);
507
508 wxShapeCanvas* canvas = lineShape->GetFrom()->GetCanvas();
509
510 wxClientDC dc(canvas);
511 canvas->PrepareDC(dc);
512
513 lineShape->GetFrom()->MoveLinks(dc);
514 lineShape->GetTo()->MoveLinks(dc);
515
516 }
2ba06d5a 517 m_shapeOnCanvas->Show(true);
1fc25a89 518
2ba06d5a 519 m_doc->Modify(true);
1fc25a89
JS
520 m_doc->UpdateAllViews();
521 break;
522 }
523 case ID_CS_ADD_SHAPE:
524 case ID_CS_ADD_LINE:
525 case ID_CS_ADD_SHAPE_SELECT:
526 case ID_CS_ADD_LINE_SELECT:
527 {
528 wxASSERT( (m_shapeOnCanvas != NULL) );
529 wxASSERT( (m_savedState == NULL) );
530 wxASSERT( (m_doc != NULL) );
531
532 // In case this is a line
533 wxShape* lineFrom = NULL;
534 wxShape* lineTo = NULL;
535 int attachmentFrom = 0, attachmentTo = 0;
536
537 if (m_shapeOnCanvas->IsKindOf(CLASSINFO(wxLineShape)))
538 {
539 // Store the from/to info to save in the line shape
540 wxLineShape* lineShape = (wxLineShape*) m_shapeOnCanvas;
541 lineFrom = lineShape->GetFrom();
542 lineTo = lineShape->GetTo();
543 attachmentFrom = lineShape->GetAttachmentFrom();
544 attachmentTo = lineShape->GetAttachmentTo();
545 }
546
547 wxClientDC dc(m_shapeOnCanvas->GetCanvas());
548 m_shapeOnCanvas->GetCanvas()->PrepareDC(dc);
549
2ba06d5a
WS
550 m_shapeOnCanvas->Select(false, &dc);
551 ((csDiagramView*) m_doc->GetFirstView())->SelectShape(m_shapeOnCanvas, false);
1fc25a89
JS
552 m_doc->GetDiagram()->RemoveShape(m_shapeOnCanvas);
553 m_shapeOnCanvas->Unlink(); // Unlinks the line, if it is a line
554
555 if (m_shapeOnCanvas->IsKindOf(CLASSINFO(wxLineShape)))
556 {
557 // Restore the from/to info for future reference
558 wxLineShape* lineShape = (wxLineShape*) m_shapeOnCanvas;
559 lineShape->SetFrom(lineFrom);
560 lineShape->SetTo(lineTo);
561 lineShape->SetAttachments(attachmentFrom, attachmentTo);
562 }
563
564 m_savedState = m_shapeOnCanvas;
565 m_shapeOnCanvas = NULL;
566
2ba06d5a 567 m_doc->Modify(true);
1fc25a89
JS
568 m_doc->UpdateAllViews();
569 break;
570 }
571 case ID_CS_CHANGE_BACKGROUND_COLOUR:
572 case ID_CS_MOVE:
573 case ID_CS_SIZE:
574 case ID_CS_EDIT_PROPERTIES:
575 case ID_CS_FONT_CHANGE:
576 case ID_CS_ARROW_CHANGE:
577 case ID_CS_ROTATE_CLOCKWISE:
578 case ID_CS_ROTATE_ANTICLOCKWISE:
579 case ID_CS_CHANGE_LINE_ORDERING:
580 case ID_CS_CHANGE_LINE_ATTACHMENT:
581 case ID_CS_ALIGN:
582 case ID_CS_NEW_POINT:
583 case ID_CS_CUT_POINT:
584 case ID_CS_MOVE_LINE_POINT:
585 case ID_CS_STRAIGHTEN:
586 case ID_CS_MOVE_LABEL:
587 {
588 // Exactly like the Do case; we're just swapping states.
589 Do();
590 break;
591 }
592 }
593
2ba06d5a 594 return true;
1fc25a89
JS
595}
596