]> git.saurik.com Git - wxWidgets.git/blame - utils/ogl/src/ogldiag.cpp
"unsigned char" restored in wxColour ctor
[wxWidgets.git] / utils / ogl / src / ogldiag.cpp
CommitLineData
0fc1a713
JS
1/////////////////////////////////////////////////////////////////////////////
2// Name: ogldiag.cpp
3// Purpose: wxDiagram
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 "ogldiag.h"
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#ifdef PROLOGIO
28#include <wx/wxexpr.h>
29#endif
30
47d67540 31#if wxUSE_IOSTREAMH
0fc1a713 32#include <iostream.h>
2910dac8 33#include <fstream.h>
0fc1a713
JS
34#else
35#include <iostream>
2910dac8
UU
36#include <fstream>
37#ifdef _MSC_VER
38using namespace std;
39#endif
0fc1a713
JS
40#endif
41
0fc1a713
JS
42#include <ctype.h>
43#include <math.h>
44#include <stdlib.h>
45
46#include "basic.h"
47#include "basicp.h"
48#include "canvas.h"
49#include "ogldiag.h"
50#include "lines.h"
51#include "composit.h"
52#include "misc.h"
53
54IMPLEMENT_DYNAMIC_CLASS(wxDiagram, wxObject)
55
56// Object canvas
57wxDiagram::wxDiagram()
58{
59 m_diagramCanvas = NULL;
60 m_quickEditMode = FALSE;
61 m_snapToGrid = TRUE;
62 m_gridSpacing = 5.0;
63 m_shapeList = new wxList;
64 m_mouseTolerance = DEFAULT_MOUSE_TOLERANCE;
65}
66
67wxDiagram::~wxDiagram()
68{
69 if (m_shapeList)
70 delete m_shapeList;
71}
72
73void wxDiagram::SetSnapToGrid(bool snap)
74{
75 m_snapToGrid = snap;
76}
77
42cfaf8c 78void wxDiagram::SetGridSpacing(double spacing)
0fc1a713
JS
79{
80 m_gridSpacing = spacing;
81}
82
42cfaf8c 83void wxDiagram::Snap(double *x, double *y)
0fc1a713
JS
84{
85 if (m_snapToGrid)
86 {
87 *x = m_gridSpacing * ((int)(*x/m_gridSpacing + 0.5));
88 *y = m_gridSpacing * ((int)(*y/m_gridSpacing + 0.5));
89 }
90}
91
92
93void wxDiagram::Redraw(wxDC& dc)
94{
95 if (m_shapeList)
96 {
97 if (GetCanvas())
98 GetCanvas()->SetCursor(wxHOURGLASS_CURSOR);
99 wxNode *current = m_shapeList->First();
100
101 while (current)
102 {
103 wxShape *object = (wxShape *)current->Data();
104 if (!object->GetParent())
105 object->Draw(dc);
106
107 current = current->Next();
108 }
109 if (GetCanvas())
110 GetCanvas()->SetCursor(wxSTANDARD_CURSOR);
111 }
112}
113
114void wxDiagram::Clear(wxDC& dc)
115{
116 dc.Clear();
117}
118
119// Insert object after addAfter, or at end of list.
120void wxDiagram::AddShape(wxShape *object, wxShape *addAfter)
121{
122 wxNode *nodeAfter = NULL;
123 if (addAfter)
124 nodeAfter = m_shapeList->Member(addAfter);
125
126 if (!m_shapeList->Member(object))
127 {
128 if (nodeAfter)
129 {
130 if (nodeAfter->Next())
131 m_shapeList->Insert(nodeAfter->Next(), object);
132 else
133 m_shapeList->Append(object);
134 }
135 else
136 m_shapeList->Append(object);
137 object->SetCanvas(GetCanvas());
138 }
139}
140
141void wxDiagram::InsertShape(wxShape *object)
142{
143 m_shapeList->Insert(object);
144 object->SetCanvas(GetCanvas());
145}
146
147void wxDiagram::RemoveShape(wxShape *object)
148{
149 m_shapeList->DeleteObject(object);
150}
151
152// Should this delete the actual objects too? I think not.
153void wxDiagram::RemoveAllShapes()
154{
155 m_shapeList->Clear();
156}
157
158void wxDiagram::DeleteAllShapes()
159{
160 wxNode *node = m_shapeList->First();
161 while (node)
162 {
163 wxShape *shape = (wxShape *)node->Data();
164 if (!shape->GetParent())
165 {
166 RemoveShape(shape);
167 delete shape;
168 node = m_shapeList->First();
169 }
170 else
171 node = node->Next();
172 }
173}
174
175void wxDiagram::ShowAll(bool show)
176{
177 wxNode *current = m_shapeList->First();
178
179 while (current)
180 {
181 wxShape *object = (wxShape *)current->Data();
182 object->Show(show);
183
184 current = current->Next();
185 }
186}
187
42cfaf8c 188void wxDiagram::DrawOutline(wxDC& dc, double x1, double y1, double x2, double y2)
0fc1a713
JS
189{
190 wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
191 dc.SetPen(dottedPen);
192 dc.SetBrush((* wxTRANSPARENT_BRUSH));
193
194 wxPoint points[5];
195
196 points[0].x = x1;
197 points[0].y = y1;
198
199 points[1].x = x2;
200 points[1].y = y1;
201
202 points[2].x = x2;
203 points[2].y = y2;
204
205 points[3].x = x1;
206 points[3].y = y2;
207
208 points[4].x = x1;
209 points[4].y = y1;
210 dc.DrawLines(5, points);
211}
212
213// Make sure all text that should be centred, is centred.
214void wxDiagram::RecentreAll(wxDC& dc)
215{
216 wxNode *object_node = m_shapeList->First();
217 while (object_node)
218 {
219 wxShape *obj = (wxShape *)object_node->Data();
220 obj->Recentre(dc);
221 object_node = object_node->Next();
222 }
223}
224
225// Input/output
226#ifdef PROLOGIO
227bool wxDiagram::SaveFile(const wxString& filename)
228{
229 wxBeginBusyCursor();
230
231 wxExprDatabase *database = new wxExprDatabase;
232
233 // First write the diagram type
234 wxExpr *header = new wxExpr("diagram");
235 OnHeaderSave(*database, *header);
236
237 database->Append(header);
238
239 wxNode *node = m_shapeList->First();
240 while (node)
241 {
242 wxShape *shape = (wxShape *)node->Data();
243
244 if (!shape->IsKindOf(CLASSINFO(wxControlPoint)))
245 {
246 wxExpr *expr = NULL;
247 if (shape->IsKindOf(CLASSINFO(wxLineShape)))
248 expr = new wxExpr("line");
249 else
250 expr = new wxExpr("shape");
251
252 OnShapeSave(*database, *shape, *expr);
253 }
254 node = node->Next();
255 }
256 OnDatabaseSave(*database);
257
258 char tempFile[400];
259 wxGetTempFileName("diag", tempFile);
260 ofstream stream(tempFile);
261 if (stream.bad())
262 {
263 wxEndBusyCursor();
264 delete database;
265 return FALSE;
266 }
267
268 database->Write(stream);
269 stream.close();
270 delete database;
271
272/*
273 // Save backup
274 if (FileExists(filename))
275 {
276 char buf[400];
277#ifdef __X__
278 sprintf(buf, "%s.bak", filename);
279#endif
280#ifdef __WXMSW__
281 sprintf(buf, "_diagram.bak");
282#endif
283 if (FileExists(buf)) wxRemoveFile(buf);
284 if (!wxRenameFile(filename, buf))
285 {
286 wxCopyFile(filename, buf);
287 wxRemoveFile(filename);
288 }
289 }
290*/
291
292 // Copy the temporary file to the correct filename
293 if (!wxRenameFile(tempFile, filename))
294 {
295 wxCopyFile(tempFile, filename);
296 wxRemoveFile(tempFile);
297 }
298
299 wxEndBusyCursor();
300 return TRUE;
301}
302
303bool wxDiagram::LoadFile(const wxString& filename)
304{
305 wxBeginBusyCursor();
306
f93ce4da 307 wxExprDatabase database(wxExprInteger, "id");
0fc1a713
JS
308 if (!database.Read(filename))
309 {
310 wxEndBusyCursor();
311 return FALSE;
312 }
313
314 DeleteAllShapes();
315
316 database.BeginFind();
317 wxExpr *header = database.FindClauseByFunctor("diagram");
318
319 if (header)
320 OnHeaderLoad(database, *header);
321
322 // Scan through all clauses and register the ids
323 wxNode *node = database.First();
324 while (node)
325 {
326 wxExpr *clause = (wxExpr *)node->Data();
327 long id = -1;
328 clause->GetAttributeValue("id", id);
329 RegisterId(id);
330 node = node->Next();
331 }
332
333 ReadNodes(database);
334 ReadContainerGeometry(database);
335 ReadLines(database);
336
337 OnDatabaseLoad(database);
338
339 wxEndBusyCursor();
340
341 return TRUE;
342}
343
344void wxDiagram::ReadNodes(wxExprDatabase& database)
345{
346 // Find and create the node images
347 database.BeginFind();
348 wxExpr *clause = database.FindClauseByFunctor("shape");
349 while (clause)
350 {
351 char *type = NULL;
352 long parentId = -1;
353
354 clause->AssignAttributeValue("type", &type);
355 clause->AssignAttributeValue("parent", &parentId);
356 wxClassInfo *classInfo = wxClassInfo::FindClass(type);
357 if (classInfo)
358 {
359 wxShape *shape = (wxShape *)classInfo->CreateObject();
360 OnShapeLoad(database, *shape, *clause);
361
362 shape->SetCanvas(GetCanvas());
363 shape->Show(TRUE);
364
365 m_shapeList->Append(shape);
366
367 // If child of composite, link up
368 if (parentId > -1)
369 {
370 wxExpr *parentExpr = database.HashFind("shape", parentId);
371 if (parentExpr && parentExpr->GetClientData())
372 {
373 wxShape *parent = (wxShape *)parentExpr->GetClientData();
374 shape->SetParent(parent);
375 parent->GetChildren().Append(shape);
376 }
377 }
378
379 clause->SetClientData(shape);
380 }
381 if (type)
382 delete[] type;
383
384 clause = database.FindClauseByFunctor("shape");
385 }
386 return;
387}
388
389void wxDiagram::ReadLines(wxExprDatabase& database)
390{
391 database.BeginFind();
392 wxExpr *clause = database.FindClauseByFunctor("line");
393 while (clause)
394 {
395 wxString type("");
396 long parentId = -1;
397
398 clause->GetAttributeValue("type", type);
399 clause->GetAttributeValue("parent", parentId);
400 wxClassInfo *classInfo = wxClassInfo::FindClass((char*) (const char*) type);
401 if (classInfo)
402 {
403 wxLineShape *shape = (wxLineShape *)classInfo->CreateObject();
404 shape->Show(TRUE);
405
406 OnShapeLoad(database, *shape, *clause);
2e5ed787 407 shape->SetCanvas(GetCanvas());
0fc1a713
JS
408
409 long image_to = -1; long image_from = -1;
410 clause->GetAttributeValue("to", image_to);
411 clause->GetAttributeValue("from", image_from);
412
413 wxExpr *image_to_expr = database.HashFind("shape", image_to);
414
415 if (!image_to_expr)
416 {
417 // Error
418 }
419 wxExpr *image_from_expr = database.HashFind("shape", image_from);
420
421 if (!image_from_expr)
422 {
423 // Error
424 }
425
426 if (image_to_expr && image_from_expr)
427 {
428 wxShape *image_to_object = (wxShape *)image_to_expr->GetClientData();
429 wxShape *image_from_object = (wxShape *)image_from_expr->GetClientData();
430
431 if (image_to_object && image_from_object)
432 {
433 image_from_object->AddLine(shape, image_to_object, shape->GetAttachmentFrom(), shape->GetAttachmentTo());
434 }
435 }
436 clause->SetClientData(shape);
437
438 m_shapeList->Append(shape);
439 }
440
441 clause = database.FindClauseByFunctor("line");
442 }
443}
444
445// Containers have divisions that reference adjoining divisions,
446// so we need a separate pass to link everything up.
447// Also used by Symbol Library.
448void wxDiagram::ReadContainerGeometry(wxExprDatabase& database)
449{
450 database.BeginFind();
451 wxExpr *clause = database.FindClauseByFunctor("shape");
452 while (clause)
453 {
454 wxShape *image = (wxShape *)clause->GetClientData();
455 if (image && image->IsKindOf(CLASSINFO(wxCompositeShape)))
456 {
457 wxCompositeShape *composite = (wxCompositeShape *)image;
458 wxExpr *divisionExpr = NULL;
459
460 // Find the list of divisions in the composite
461 clause->GetAttributeValue("divisions", &divisionExpr);
462 if (divisionExpr)
463 {
464 int i = 0;
465 wxExpr *idExpr = divisionExpr->Nth(i);
466 while (idExpr)
467 {
468 long divisionId = idExpr->IntegerValue();
469 wxExpr *childExpr = database.HashFind("shape", divisionId);
470 if (childExpr && childExpr->GetClientData())
471 {
472 wxDivisionShape *child = (wxDivisionShape *)childExpr->GetClientData();
473 composite->GetDivisions().Append(child);
474
475 // Find the adjoining shapes
476 long leftSideId = -1;
477 long topSideId = -1;
478 long rightSideId = -1;
479 long bottomSideId = -1;
480 childExpr->GetAttributeValue("left_side", leftSideId);
481 childExpr->GetAttributeValue("top_side", topSideId);
482 childExpr->GetAttributeValue("right_side", rightSideId);
483 childExpr->GetAttributeValue("bottom_side", bottomSideId);
484 if (leftSideId > -1)
485 {
486 wxExpr *leftExpr = database.HashFind("shape", leftSideId);
487 if (leftExpr && leftExpr->GetClientData())
488 {
489 wxDivisionShape *leftSide = (wxDivisionShape *)leftExpr->GetClientData();
490 child->SetLeftSide(leftSide);
491 }
492 }
493 if (topSideId > -1)
494 {
495 wxExpr *topExpr = database.HashFind("shape", topSideId);
496 if (topExpr && topExpr->GetClientData())
497 {
498 wxDivisionShape *topSide = (wxDivisionShape *)topExpr->GetClientData();
499 child->SetTopSide(topSide);
500 }
501 }
502 if (rightSideId > -1)
503 {
504 wxExpr *rightExpr = database.HashFind("shape", rightSideId);
505 if (rightExpr && rightExpr->GetClientData())
506 {
507 wxDivisionShape *rightSide = (wxDivisionShape *)rightExpr->GetClientData();
508 child->SetRightSide(rightSide);
509 }
510 }
511 if (bottomSideId > -1)
512 {
513 wxExpr *bottomExpr = database.HashFind("shape", bottomSideId);
514 if (bottomExpr && bottomExpr->GetClientData())
515 {
516 wxDivisionShape *bottomSide = (wxDivisionShape *)bottomExpr->GetClientData();
517 child->SetBottomSide(bottomSide);
518 }
519 }
520 }
521 i ++;
522 idExpr = divisionExpr->Nth(i);
523 }
524 }
525 }
526
527 clause = database.FindClauseByFunctor("shape");
528 }
529}
530
531// Allow for modifying file
532bool wxDiagram::OnDatabaseLoad(wxExprDatabase& db)
533{
534 return TRUE;
535}
536
537bool wxDiagram::OnDatabaseSave(wxExprDatabase& db)
538{
539 return TRUE;
540}
541
542bool wxDiagram::OnShapeSave(wxExprDatabase& db, wxShape& shape, wxExpr& expr)
543{
6f5f3ca0 544 shape.WriteAttributes(&expr);
0fc1a713
JS
545 db.Append(&expr);
546
547 if (shape.IsKindOf(CLASSINFO(wxCompositeShape)))
548 {
549 wxNode *node = shape.GetChildren().First();
550 while (node)
551 {
552 wxShape *childShape = (wxShape *)node->Data();
553 wxExpr *childExpr = new wxExpr("shape");
554 OnShapeSave(db, *childShape, *childExpr);
555 node = node->Next();
556 }
557 }
558
559 return TRUE;
560}
561
562bool wxDiagram::OnShapeLoad(wxExprDatabase& db, wxShape& shape, wxExpr& expr)
563{
6f5f3ca0 564 shape.ReadAttributes(&expr);
0fc1a713
JS
565 return TRUE;
566}
567
568bool wxDiagram::OnHeaderSave(wxExprDatabase& db, wxExpr& expr)
569{
570 return TRUE;
571}
572
573bool wxDiagram::OnHeaderLoad(wxExprDatabase& db, wxExpr& expr)
574{
575 return TRUE;
576}
577
578#endif
579
580void wxDiagram::SetCanvas(wxShapeCanvas *can)
581{
582 m_diagramCanvas = can;
583}
584
f93ce4da
JS
585// Find a shape by its id
586wxShape* wxDiagram::FindShape(long id) const
587{
588 wxNode* node = GetShapeList()->First();
589 while (node)
590 {
591 wxShape* shape = (wxShape*) node->Data();
592 if (shape->GetId() == id)
593 return shape;
594 node = node->Next();
595 }
596 return NULL;
597}
0fc1a713 598
f97c9854
JS
599
600//// Crossings classes
601
602wxLineCrossings::wxLineCrossings()
603{
604}
605
606wxLineCrossings::~wxLineCrossings()
607{
608 ClearCrossings();
609}
610
611void wxLineCrossings::FindCrossings(wxDiagram& diagram)
612{
613 ClearCrossings();
614 wxNode* node1 = diagram.GetShapeList()->First();
615 while (node1)
616 {
617 wxShape* shape1 = (wxShape*) node1->Data();
618 if (shape1->IsKindOf(CLASSINFO(wxLineShape)))
619 {
620 wxLineShape* lineShape1 = (wxLineShape*) shape1;
621 // Iterate through the segments
622 wxList* pts1 = lineShape1->GetLineControlPoints();
623 int i;
624 for (i = 0; i < (pts1->Number() - 1); i++)
625 {
626 wxRealPoint* pt1_a = (wxRealPoint*) (pts1->Nth(i)->Data());
627 wxRealPoint* pt1_b = (wxRealPoint*) (pts1->Nth(i+1)->Data());
628
629 // Now we iterate through the segments again
630
631 wxNode* node2 = diagram.GetShapeList()->First();
632 while (node2)
633 {
634 wxShape* shape2 = (wxShape*) node2->Data();
635
636 // Assume that the same line doesn't cross itself
637 if (shape2->IsKindOf(CLASSINFO(wxLineShape)) && (shape1 != shape2))
638 {
639 wxLineShape* lineShape2 = (wxLineShape*) shape2;
640 // Iterate through the segments
641 wxList* pts2 = lineShape2->GetLineControlPoints();
642 int j;
643 for (j = 0; j < (pts2->Number() - 1); j++)
644 {
645 wxRealPoint* pt2_a = (wxRealPoint*) (pts2->Nth(j)->Data());
646 wxRealPoint* pt2_b = (wxRealPoint*) (pts2->Nth(j+1)->Data());
647
648 // Now let's see if these two segments cross.
649 double ratio1, ratio2;
650 oglCheckLineIntersection(pt1_a->x, pt1_a->y, pt1_b->x, pt1_b->y,
651 pt2_a->x, pt2_a->y, pt2_b->x, pt2_b->y,
652 & ratio1, & ratio2);
653
654 if ((ratio1 < 1.0) && (ratio1 > -1.0))
655 {
656 // Intersection!
657 wxLineCrossing* crossing = new wxLineCrossing;
658 crossing->m_intersect.x = (pt1_a->x + (pt1_b->x - pt1_a->x)*ratio1);
659 crossing->m_intersect.y = (pt1_a->y + (pt1_b->y - pt1_a->y)*ratio1);
660
661 crossing->m_pt1 = * pt1_a;
662 crossing->m_pt2 = * pt1_b;
663 crossing->m_pt3 = * pt2_a;
664 crossing->m_pt4 = * pt2_b;
665
666 crossing->m_lineShape1 = lineShape1;
667 crossing->m_lineShape2 = lineShape2;
668
669 m_crossings.Append(crossing);
670 }
671 }
672 }
673 node2 = node2->Next();
674 }
675 }
676 }
677
678 node1 = node1->Next();
679 }
680}
681
682void wxLineCrossings::DrawCrossings(wxDiagram& diagram, wxDC& dc)
683{
684 dc.SetBrush(*wxTRANSPARENT_BRUSH);
685
686 long arcWidth = 8;
687
688 wxNode* node = m_crossings.First();
689 while (node)
690 {
691 wxLineCrossing* crossing = (wxLineCrossing*) node->Data();
692// dc.DrawEllipse((long) (crossing->m_intersect.x - (arcWidth/2.0) + 0.5), (long) (crossing->m_intersect.y - (arcWidth/2.0) + 0.5),
693// arcWidth, arcWidth);
694
695
696 // Let's do some geometry to find the points on either end of the arc.
697/*
698
699(x1, y1)
700 |\
701 | \
702 | \
703 | \
704 | \
705 | |\ c c1
706 | a | \
707 | \
708 | - x <-- centre of arc
709 a1 | b |\
710 | | \ c2
711 | a2 | \
712 | - \
713 | b2 \
714 | \
715 |_______________\ (x2, y2)
716 b1
717
718*/
719
720 double a1 = wxMax(crossing->m_pt1.y, crossing->m_pt2.y) - wxMin(crossing->m_pt1.y, crossing->m_pt2.y) ;
721 double b1 = wxMax(crossing->m_pt1.x, crossing->m_pt2.x) - wxMin(crossing->m_pt1.x, crossing->m_pt2.x) ;
722 double c1 = sqrt( (a1*a1) + (b1*b1) );
723
724 double c = arcWidth / 2.0;
725 double a = c * a1/c1 ;
726 double b = c * b1/c1 ;
727
728 // I'm not sure this is right, since we don't know which direction we should be going in - need
729 // to know which way the line slopes and choose the sign appropriately.
730 double arcX1 = crossing->m_intersect.x - b;
731 double arcY1 = crossing->m_intersect.y - a;
732
733 double arcX2 = crossing->m_intersect.x + b;
734 double arcY2 = crossing->m_intersect.y + a;
735
736 dc.SetPen(*wxBLACK_PEN);
737 dc.DrawArc( (long) arcX1, (long) arcY1, (long) arcX2, (long) arcY2,
738 (long) crossing->m_intersect.x, (long) crossing->m_intersect.y);
739
740 dc.SetPen(*wxWHITE_PEN);
741 dc.DrawLine( (long) arcX1, (long) arcY1, (long) arcX2, (long) arcY2 );
742
743 node = node->Next();
744 }
745}
746
747void wxLineCrossings::ClearCrossings()
748{
749 wxNode* node = m_crossings.First();
750 while (node)
751 {
752 wxLineCrossing* crossing = (wxLineCrossing*) node->Data();
753 delete crossing;
754 node = node->Next();
755 }
756 m_crossings.Clear();
757}
758