]> git.saurik.com Git - wxWidgets.git/blob - utils/ogl/src/basic.cpp
Added revamped Object Graphics Library (for node/arc diagrams).
[wxWidgets.git] / utils / ogl / src / basic.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: basic.cpp
3 // Purpose: Basic OGL classes
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 "basic.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
31 #if USE_IOSTREAMH
32 #include <iostream.h>
33 #else
34 #include <iostream>
35 #endif
36
37 #include <stdio.h>
38 #include <ctype.h>
39 #include <math.h>
40
41 #include "basic.h"
42 #include "basicp.h"
43 #include "composit.h"
44 #include "lines.h"
45 #include "canvas.h"
46 #include "divided.h"
47 #include "misc.h"
48
49 // Control point types
50 // Rectangle and most other shapes
51 #define CONTROL_POINT_VERTICAL 1
52 #define CONTROL_POINT_HORIZONTAL 2
53 #define CONTROL_POINT_DIAGONAL 3
54
55 // Line
56 #define CONTROL_POINT_ENDPOINT_TO 4
57 #define CONTROL_POINT_ENDPOINT_FROM 5
58 #define CONTROL_POINT_LINE 6
59
60 IMPLEMENT_DYNAMIC_CLASS(wxShapeTextLine, wxObject)
61 IMPLEMENT_DYNAMIC_CLASS(wxAttachmentPoint, wxObject)
62
63 wxShapeTextLine::wxShapeTextLine(float the_x, float the_y, const wxString& the_line)
64 {
65 m_x = the_x; m_y = the_y; m_line = the_line;
66 }
67
68 wxShapeTextLine::~wxShapeTextLine()
69 {
70 }
71
72 IMPLEMENT_ABSTRACT_CLASS(wxShapeEvtHandler, wxObject)
73
74 wxShapeEvtHandler::wxShapeEvtHandler(wxShapeEvtHandler *prev, wxShape *shape)
75 {
76 m_previousHandler = prev;
77 m_handlerShape = shape;
78 }
79
80 wxShapeEvtHandler::~wxShapeEvtHandler()
81 {
82 }
83
84 void wxShapeEvtHandler::OnDelete()
85 {
86 if (this != GetShape())
87 delete this;
88 }
89
90 void wxShapeEvtHandler::OnDraw(wxDC& dc)
91 {
92 if (m_previousHandler)
93 m_previousHandler->OnDraw(dc);
94 }
95
96 void wxShapeEvtHandler::OnMoveLinks(wxDC& dc)
97 {
98 if (m_previousHandler)
99 m_previousHandler->OnMoveLinks(dc);
100 }
101
102 void wxShapeEvtHandler::OnMoveLink(wxDC& dc, bool moveControlPoints)
103 {
104 if (m_previousHandler)
105 m_previousHandler->OnMoveLink(dc, moveControlPoints);
106 }
107
108 void wxShapeEvtHandler::OnDrawContents(wxDC& dc)
109 {
110 if (m_previousHandler)
111 m_previousHandler->OnDrawContents(dc);
112 }
113
114 void wxShapeEvtHandler::OnSize(float x, float y)
115 {
116 if (m_previousHandler)
117 m_previousHandler->OnSize(x, y);
118 }
119
120 bool wxShapeEvtHandler::OnMovePre(wxDC& dc, float x, float y, float old_x, float old_y, bool display)
121 {
122 if (m_previousHandler)
123 return m_previousHandler->OnMovePre(dc, x, y, old_x, old_y, display);
124 else
125 return TRUE;
126 }
127
128 void wxShapeEvtHandler::OnMovePost(wxDC& dc, float x, float y, float old_x, float old_y, bool display)
129 {
130 if (m_previousHandler)
131 m_previousHandler->OnMovePost(dc, x, y, old_x, old_y, display);
132 }
133
134 void wxShapeEvtHandler::OnErase(wxDC& dc)
135 {
136 if (m_previousHandler)
137 m_previousHandler->OnErase(dc);
138 }
139
140 void wxShapeEvtHandler::OnEraseContents(wxDC& dc)
141 {
142 if (m_previousHandler)
143 m_previousHandler->OnEraseContents(dc);
144 }
145
146 void wxShapeEvtHandler::OnHighlight(wxDC& dc)
147 {
148 if (m_previousHandler)
149 m_previousHandler->OnHighlight(dc);
150 }
151
152 void wxShapeEvtHandler::OnLeftClick(float x, float y, int keys, int attachment)
153 {
154 if (m_previousHandler)
155 m_previousHandler->OnLeftClick(x, y, keys, attachment);
156 }
157
158 void wxShapeEvtHandler::OnRightClick(float x, float y, int keys, int attachment)
159 {
160 if (m_previousHandler)
161 m_previousHandler->OnRightClick(x, y, keys, attachment);
162 }
163
164 void wxShapeEvtHandler::OnDragLeft(bool draw, float x, float y, int keys, int attachment)
165 {
166 if (m_previousHandler)
167 m_previousHandler->OnDragLeft(draw, x, y, keys, attachment);
168 }
169
170 void wxShapeEvtHandler::OnBeginDragLeft(float x, float y, int keys, int attachment)
171 {
172 if (m_previousHandler)
173 m_previousHandler->OnBeginDragLeft(x, y, keys, attachment);
174 }
175
176 void wxShapeEvtHandler::OnEndDragLeft(float x, float y, int keys, int attachment)
177 {
178 if (m_previousHandler)
179 m_previousHandler->OnEndDragLeft(x, y, keys, attachment);
180 }
181
182 void wxShapeEvtHandler::OnDragRight(bool draw, float x, float y, int keys, int attachment)
183 {
184 if (m_previousHandler)
185 m_previousHandler->OnDragRight(draw, x, y, keys, attachment);
186 }
187
188 void wxShapeEvtHandler::OnBeginDragRight(float x, float y, int keys, int attachment)
189 {
190 if (m_previousHandler)
191 m_previousHandler->OnBeginDragRight(x, y, keys, attachment);
192 }
193
194 void wxShapeEvtHandler::OnEndDragRight(float x, float y, int keys, int attachment)
195 {
196 if (m_previousHandler)
197 m_previousHandler->OnEndDragRight(x, y, keys, attachment);
198 }
199
200 void wxShapeEvtHandler::OnDrawOutline(wxDC& dc, float x, float y, float w, float h)
201 {
202 if (m_previousHandler)
203 m_previousHandler->OnDrawOutline(dc, x, y, w, h);
204 }
205
206 void wxShapeEvtHandler::OnDrawControlPoints(wxDC& dc)
207 {
208 if (m_previousHandler)
209 m_previousHandler->OnDrawControlPoints(dc);
210 }
211
212 void wxShapeEvtHandler::OnEraseControlPoints(wxDC& dc)
213 {
214 if (m_previousHandler)
215 m_previousHandler->OnEraseControlPoints(dc);
216 }
217
218 IMPLEMENT_ABSTRACT_CLASS(wxShape, wxShapeEvtHandler)
219
220 wxShape::wxShape(wxShapeCanvas *can)
221 {
222 m_eventHandler = this;
223 SetHandlerShape(this);
224 m_id = 0;
225 m_formatted = FALSE;
226 m_canvas = can;
227 m_xpos = 0.0; m_ypos = 0.0;
228 m_pen = black_pen;
229 m_brush = wxWHITE_BRUSH;
230 m_font = g_oglNormalFont;
231 m_textColour = wxBLACK;
232 m_textColourName = "BLACK";
233 m_visible = FALSE;
234 m_clientData = NULL;
235 m_selected = FALSE;
236 m_attachmentMode = FALSE;
237 m_spaceAttachments = TRUE;
238 m_disableLabel = FALSE;
239 m_fixedWidth = FALSE;
240 m_fixedHeight = FALSE;
241 m_drawHandles = TRUE;
242 m_sensitivity = OP_ALL;
243 m_draggable = TRUE;
244 m_parent = NULL;
245 m_formatMode = FORMAT_CENTRE_HORIZ | FORMAT_CENTRE_VERT;
246 m_shadowMode = SHADOW_NONE;
247 m_shadowOffsetX = 6.0;
248 m_shadowOffsetY = 6.0;
249 m_shadowBrush = wxBLACK_BRUSH;
250 m_textMarginX = 5.0;
251 m_textMarginY = 5.0;
252 m_regionName = "0";
253 m_centreResize = TRUE;
254 m_highlighted = FALSE;
255 m_rotation = 0.0;
256
257 // Set up a default region. Much of the above will be put into
258 // the region eventually (the duplication is for compatibility)
259 wxShapeRegion *region = new wxShapeRegion;
260 m_regions.Append(region);
261 region->SetName("0");
262 region->SetFont(g_oglNormalFont);
263 region->SetFormatMode(FORMAT_CENTRE_HORIZ | FORMAT_CENTRE_VERT);
264 region->SetColour("BLACK");
265 }
266
267 wxShape::~wxShape()
268 {
269 if (m_parent)
270 m_parent->GetChildren().DeleteObject(this);
271
272 ClearText();
273 ClearRegions();
274 ClearAttachments();
275
276 if (m_canvas)
277 m_canvas->RemoveShape(this);
278
279 GetEventHandler()->OnDelete();
280 }
281
282 void wxShape::SetHighlight(bool hi, bool recurse)
283 {
284 m_highlighted = hi;
285 if (recurse)
286 {
287 wxNode *node = m_children.First();
288 while (node)
289 {
290 wxShape *child = (wxShape *)node->Data();
291 child->SetHighlight(hi, recurse);
292 node = node->Next();
293 }
294 }
295 }
296
297 void wxShape::SetSensitivityFilter(int sens, bool recursive)
298 {
299 if (sens & OP_DRAG_LEFT)
300 m_draggable = TRUE;
301 else
302 m_draggable = FALSE;
303
304 m_sensitivity = sens;
305 if (recursive)
306 {
307 wxNode *node = m_children.First();
308 while (node)
309 {
310 wxShape *obj = (wxShape *)node->Data();
311 obj->SetSensitivityFilter(sens, TRUE);
312 node = node->Next();
313 }
314 }
315 }
316
317 void wxShape::SetDraggable(bool drag, bool recursive)
318 {
319 m_draggable = drag;
320 if (m_draggable)
321 m_sensitivity |= OP_DRAG_LEFT;
322 else
323 if (m_sensitivity & OP_DRAG_LEFT)
324 m_sensitivity = m_sensitivity - OP_DRAG_LEFT;
325
326 if (recursive)
327 {
328 wxNode *node = m_children.First();
329 while (node)
330 {
331 wxShape *obj = (wxShape *)node->Data();
332 obj->SetDraggable(drag, TRUE);
333 node = node->Next();
334 }
335 }
336 }
337
338 void wxShape::SetDrawHandles(bool drawH)
339 {
340 m_drawHandles = drawH;
341 wxNode *node = m_children.First();
342 while (node)
343 {
344 wxShape *obj = (wxShape *)node->Data();
345 obj->SetDrawHandles(drawH);
346 node = node->Next();
347 }
348 }
349
350 void wxShape::SetShadowMode(int mode, bool redraw)
351 {
352 if (redraw && GetCanvas())
353 {
354 wxClientDC dc(GetCanvas());
355 GetCanvas()->PrepareDC(dc);
356 Erase(dc);
357
358 m_shadowMode = mode;
359
360 Draw(dc);
361 }
362 else
363 {
364 m_shadowMode = mode;
365 }
366 }
367
368 void wxShape::SetCanvas(wxShapeCanvas *theCanvas)
369 {
370 m_canvas = theCanvas;
371 wxNode *node = m_children.First();
372 while (node)
373 {
374 wxShape *child = (wxShape *)node->Data();
375 child->SetCanvas(theCanvas);
376 node = node->Next();
377 }
378 }
379
380 void wxShape::AddToCanvas(wxShapeCanvas *theCanvas, wxShape *addAfter)
381 {
382 theCanvas->AddShape(this, addAfter);
383 wxNode *node = m_children.First();
384 wxShape *lastImage = this;
385 while (node)
386 {
387 wxShape *object = (wxShape *)node->Data();
388 object->AddToCanvas(theCanvas, lastImage);
389 lastImage = object;
390
391 node = node->Next();
392 }
393 }
394
395 // Insert at front of canvas
396 void wxShape::InsertInCanvas(wxShapeCanvas *theCanvas)
397 {
398 theCanvas->InsertShape(this);
399 wxNode *node = m_children.First();
400 wxShape *lastImage = this;
401 while (node)
402 {
403 wxShape *object = (wxShape *)node->Data();
404 object->AddToCanvas(theCanvas, lastImage);
405 lastImage = object;
406
407 node = node->Next();
408 }
409 }
410
411 void wxShape::RemoveFromCanvas(wxShapeCanvas *theCanvas)
412 {
413 if (Selected())
414 Select(FALSE);
415 theCanvas->RemoveShape(this);
416 wxNode *node = m_children.First();
417 while (node)
418 {
419 wxShape *object = (wxShape *)node->Data();
420 object->RemoveFromCanvas(theCanvas);
421
422 node = node->Next();
423 }
424 }
425
426 void wxShape::ClearAttachments()
427 {
428 wxNode *node = m_attachmentPoints.First();
429 while (node)
430 {
431 wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
432 delete point;
433 node = node->Next();
434 }
435 m_attachmentPoints.Clear();
436 }
437
438 void wxShape::ClearText(int regionId)
439 {
440 if (regionId == 0)
441 {
442 m_text.DeleteContents(TRUE);
443 m_text.Clear();
444 m_text.DeleteContents(FALSE);
445 }
446 wxNode *node = m_regions.Nth(regionId);
447 if (!node)
448 return;
449 wxShapeRegion *region = (wxShapeRegion *)node->Data();
450 region->ClearText();
451 }
452
453 void wxShape::ClearRegions()
454 {
455 wxNode *node = m_regions.First();
456 while (node)
457 {
458 wxShapeRegion *region = (wxShapeRegion *)node->Data();
459 wxNode *next = node->Next();
460 delete region;
461 delete node;
462 node = next;
463 }
464 }
465
466 void wxShape::AddRegion(wxShapeRegion *region)
467 {
468 m_regions.Append(region);
469 }
470
471 void wxShape::SetDefaultRegionSize()
472 {
473 wxNode *node = m_regions.First();
474 if (!node) return;
475 wxShapeRegion *region = (wxShapeRegion *)node->Data();
476 float w, h;
477 GetBoundingBoxMin(&w, &h);
478 region->SetSize(w, h);
479 }
480
481 bool wxShape::HitTest(float x, float y, int *attachment, float *distance)
482 {
483 // if (!sensitive)
484 // return FALSE;
485
486 float width = 0.0, height = 0.0;
487 GetBoundingBoxMin(&width, &height);
488 if (fabs(width) < 4.0) width = 4.0;
489 if (fabs(height) < 4.0) height = 4.0;
490
491 width += (float)4.0; height += (float)4.0; // Allowance for inaccurate mousing
492
493 float left = (float)(m_xpos - (width/2.0));
494 float top = (float)(m_ypos - (height/2.0));
495 float right = (float)(m_xpos + (width/2.0));
496 float bottom = (float)(m_ypos + (height/2.0));
497
498 int nearest_attachment = 0;
499
500
501 // If within the bounding box, check the attachment points
502 // within the object.
503
504 if (x >= left && x <= right && y >= top && y <= bottom)
505 {
506 int n = GetNumberOfAttachments();
507 float nearest = 999999.0;
508
509 for (int i = 0; i < n; i++)
510 {
511 float xp, yp;
512 if (GetAttachmentPosition(i, &xp, &yp))
513 {
514 float l = (float)sqrt(((xp - x) * (xp - x)) +
515 ((yp - y) * (yp - y)));
516
517 if (l < nearest)
518 {
519 nearest = l;
520 nearest_attachment = i;
521 }
522 }
523 }
524 *attachment = nearest_attachment;
525 *distance = nearest;
526 return TRUE;
527 }
528 else return FALSE;
529 }
530
531 // Format a text string according to the region size, adding
532 // strings with positions to region text list
533
534 static bool GraphicsInSizeToContents = FALSE; // Infinite recursion elimination
535 void wxShape::FormatText(wxDC& dc, const wxString& s, int i)
536 {
537 float w, h;
538 ClearText(i);
539
540 if (m_regions.Number() < 1)
541 return;
542 wxNode *node = m_regions.Nth(i);
543 if (!node)
544 return;
545
546 wxShapeRegion *region = (wxShapeRegion *)node->Data();
547 region->SetText(s);
548 dc.SetFont(region->GetFont());
549
550 region->GetSize(&w, &h);
551
552 wxList *string_list = ::FormatText(dc, s, (w-5), (h-5), region->GetFormatMode());
553 node = string_list->First();
554 while (node)
555 {
556 char *s = (char *)node->Data();
557 wxShapeTextLine *line = new wxShapeTextLine(0.0, 0.0, s);
558 region->GetFormattedText().Append((wxObject *)line);
559 delete node;
560 node = string_list->First();
561 }
562 delete string_list;
563 float actualW = w;
564 float actualH = h;
565 // Don't try to resize an object with more than one image (this case should be dealt
566 // with by overriden handlers)
567 if ((region->GetFormatMode() & FORMAT_SIZE_TO_CONTENTS) &&
568 (region->GetFormattedText().Number() > 0) &&
569 (m_regions.Number() == 1) && !GraphicsInSizeToContents)
570 {
571 GetCentredTextExtent(dc, &(region->GetFormattedText()), m_xpos, m_ypos, w, h, &actualW, &actualH);
572 if ((actualW+m_textMarginX != w ) || (actualH+m_textMarginY != h))
573 {
574 // If we are a descendant of a composite, must make sure the composite gets
575 // resized properly
576 wxShape *topAncestor = GetTopAncestor();
577
578 if (topAncestor != this)
579 {
580 // Make sure we don't recurse infinitely
581 GraphicsInSizeToContents = TRUE;
582
583 wxCompositeShape *composite = (wxCompositeShape *)topAncestor;
584 composite->Erase(dc);
585 SetSize(actualW+m_textMarginX, actualH+m_textMarginY);
586 Move(dc, m_xpos, m_ypos);
587 composite->CalculateSize();
588 if (composite->Selected())
589 {
590 composite->DeleteControlPoints(& dc);
591 composite->MakeControlPoints();
592 composite->MakeMandatoryControlPoints();
593 }
594 // Where infinite recursion might happen if we didn't stop it
595 composite->Draw(dc);
596
597 GraphicsInSizeToContents = FALSE;
598 }
599 else
600 {
601 Erase(dc);
602 SetSize(actualW+m_textMarginX, actualH+m_textMarginY);
603 Move(dc, m_xpos, m_ypos);
604 }
605 SetSize(actualW+m_textMarginX, actualH+m_textMarginY);
606 Move(dc, m_xpos, m_ypos);
607 EraseContents(dc);
608 }
609 }
610 CentreText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, actualW, actualH, region->GetFormatMode());
611 m_formatted = TRUE;
612 }
613
614 void wxShape::Recentre(wxDC& dc)
615 {
616 float w, h;
617 GetBoundingBoxMin(&w, &h);
618
619 int noRegions = m_regions.Number();
620 for (int i = 0; i < noRegions; i++)
621 {
622 wxNode *node = m_regions.Nth(i);
623 if (node)
624 {
625 wxShapeRegion *region = (wxShapeRegion *)node->Data();
626 CentreText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, w, h, region->GetFormatMode());
627 }
628 }
629 }
630
631 bool wxShape::GetPerimeterPoint(float x1, float y1,
632 float x2, float y2,
633 float *x3, float *y3)
634 {
635 return FALSE;
636 }
637
638 void wxShape::SetPen(wxPen *the_pen)
639 {
640 m_pen = the_pen;
641 }
642
643 void wxShape::SetBrush(wxBrush *the_brush)
644 {
645 m_brush = the_brush;
646 }
647
648 // Get the top-most (non-division) ancestor, or self
649 wxShape *wxShape::GetTopAncestor()
650 {
651 if (!GetParent())
652 return this;
653
654 if (GetParent()->IsKindOf(CLASSINFO(wxDivisionShape)))
655 return this;
656 else return GetParent()->GetTopAncestor();
657 }
658
659 /*
660 * Region functions
661 *
662 */
663 void wxShape::SetFont(wxFont *the_font, int regionId)
664 {
665 m_font = the_font;
666 wxNode *node = m_regions.Nth(regionId);
667 if (!node)
668 return;
669 wxShapeRegion *region = (wxShapeRegion *)node->Data();
670 region->SetFont(the_font);
671 }
672
673 wxFont *wxShape::GetFont(int n) const
674 {
675 wxNode *node = m_regions.Nth(n);
676 if (!node)
677 return NULL;
678 wxShapeRegion *region = (wxShapeRegion *)node->Data();
679 return region->GetFont();
680 }
681
682 void wxShape::SetFormatMode(int mode, int regionId)
683 {
684 wxNode *node = m_regions.Nth(regionId);
685 if (!node)
686 return;
687 wxShapeRegion *region = (wxShapeRegion *)node->Data();
688 region->SetFormatMode(mode);
689 }
690
691 int wxShape::GetFormatMode(int regionId) const
692 {
693 wxNode *node = m_regions.Nth(regionId);
694 if (!node)
695 return 0;
696 wxShapeRegion *region = (wxShapeRegion *)node->Data();
697 return region->GetFormatMode();
698 }
699
700 void wxShape::SetTextColour(const wxString& the_colour, int regionId)
701 {
702 wxColour *wxcolour = wxTheColourDatabase->FindColour(the_colour);
703 m_textColour = wxcolour;
704 m_textColourName = the_colour;
705
706 wxNode *node = m_regions.Nth(regionId);
707 if (!node)
708 return;
709 wxShapeRegion *region = (wxShapeRegion *)node->Data();
710 region->SetColour(the_colour);
711 }
712
713 wxString wxShape::GetTextColour(int regionId) const
714 {
715 wxNode *node = m_regions.Nth(regionId);
716 if (!node)
717 return wxString("");
718 wxShapeRegion *region = (wxShapeRegion *)node->Data();
719 return region->GetColour();
720 }
721
722 void wxShape::SetRegionName(const wxString& name, int regionId)
723 {
724 wxNode *node = m_regions.Nth(regionId);
725 if (!node)
726 return;
727 wxShapeRegion *region = (wxShapeRegion *)node->Data();
728 region->SetName(name);
729 }
730
731 wxString wxShape::GetRegionName(int regionId)
732 {
733 wxNode *node = m_regions.Nth(regionId);
734 if (!node)
735 return wxString("");
736 wxShapeRegion *region = (wxShapeRegion *)node->Data();
737 return region->GetName();
738 }
739
740 int wxShape::GetRegionId(const wxString& name)
741 {
742 wxNode *node = m_regions.First();
743 int i = 0;
744 while (node)
745 {
746 wxShapeRegion *region = (wxShapeRegion *)node->Data();
747 if (region->GetName() == name)
748 return i;
749 node = node->Next();
750 i ++;
751 }
752 return -1;
753 }
754
755 // Name all m_regions in all subimages recursively.
756 void wxShape::NameRegions(const wxString& parentName)
757 {
758 int n = GetNumberOfTextRegions();
759 char buf[100];
760 for (int i = 0; i < n; i++)
761 {
762 if (parentName.Length() > 0)
763 sprintf(buf, "%s.%d", (const char*) parentName, i);
764 else
765 sprintf(buf, "%d", i);
766 SetRegionName(buf, i);
767 }
768 wxNode *node = m_children.First();
769 int j = 0;
770 while (node)
771 {
772 wxShape *child = (wxShape *)node->Data();
773 if (parentName.Length() > 0)
774 sprintf(buf, "%s.%d", (const char*) parentName, j);
775 else
776 sprintf(buf, "%d", j);
777 child->NameRegions(buf);
778 node = node->Next();
779 j ++;
780 }
781 }
782
783 // Get a region by name, possibly looking recursively into composites.
784 wxShape *wxShape::FindRegion(const wxString& name, int *regionId)
785 {
786 int id = GetRegionId(name);
787 if (id > -1)
788 {
789 *regionId = id;
790 return this;
791 }
792
793 wxNode *node = m_children.First();
794 while (node)
795 {
796 wxShape *child = (wxShape *)node->Data();
797 wxShape *actualImage = child->FindRegion(name, regionId);
798 if (actualImage)
799 return actualImage;
800 node = node->Next();
801 }
802 return NULL;
803 }
804
805 // Finds all region names for this image (composite or simple).
806 // Supply empty string list.
807 void wxShape::FindRegionNames(wxStringList& list)
808 {
809 int n = GetNumberOfTextRegions();
810 for (int i = 0; i < n; i++)
811 {
812 wxString name(GetRegionName(i));
813 list.Add((const char*) name);
814 }
815
816 wxNode *node = m_children.First();
817 while (node)
818 {
819 wxShape *child = (wxShape *)node->Data();
820 child->FindRegionNames(list);
821 node = node->Next();
822 }
823 }
824
825 void wxShape::AssignNewIds()
826 {
827 if (m_id == 0)
828 m_id = NewId();
829 wxNode *node = m_children.First();
830 while (node)
831 {
832 wxShape *child = (wxShape *)node->Data();
833 child->AssignNewIds();
834 node = node->Next();
835 }
836 }
837
838 void wxShape::OnDraw(wxDC& dc)
839 {
840 }
841
842 void wxShape::OnMoveLinks(wxDC& dc)
843 {
844 // Want to set the ends of all attached links
845 // to point to/from this object
846
847 wxNode *current = m_lines.First();
848 while (current)
849 {
850 wxLineShape *line = (wxLineShape *)current->Data();
851 line->GetEventHandler()->OnMoveLink(dc);
852 current = current->Next();
853 }
854 }
855
856
857 void wxShape::OnDrawContents(wxDC& dc)
858 {
859 float bound_x, bound_y;
860 GetBoundingBoxMin(&bound_x, &bound_y);
861 if (m_regions.Number() < 1) return;
862
863 if (m_pen) dc.SetPen(m_pen);
864
865 wxShapeRegion *region = (wxShapeRegion *)m_regions.First()->Data();
866 if (region->GetFont()) dc.SetFont(region->GetFont());
867
868 dc.SetTextForeground(* (region->GetActualColourObject()));
869 dc.SetBackgroundMode(wxTRANSPARENT);
870 if (!m_formatted)
871 {
872 CentreText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, bound_x, bound_y, region->GetFormatMode());
873 m_formatted = TRUE;
874 }
875 if (!GetDisableLabel())
876 {
877 DrawFormattedText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, bound_x, bound_y, region->GetFormatMode());
878 }
879 }
880
881 void wxShape::DrawContents(wxDC& dc)
882 {
883 GetEventHandler()->OnDrawContents(dc);
884 }
885
886 void wxShape::OnSize(float x, float y)
887 {
888 }
889
890 bool wxShape::OnMovePre(wxDC& dc, float x, float y, float old_x, float old_y, bool display)
891 {
892 return TRUE;
893 }
894
895 void wxShape::OnMovePost(wxDC& dc, float x, float y, float old_x, float old_y, bool display)
896 {
897 }
898
899 void wxShape::OnErase(wxDC& dc)
900 {
901 if (!m_visible)
902 return;
903
904 // Erase links
905 wxNode *current = m_lines.First();
906 while (current)
907 {
908 wxLineShape *line = (wxLineShape *)current->Data();
909 line->GetEventHandler()->OnErase(dc);
910 current = current->Next();
911 }
912 GetEventHandler()->OnEraseContents(dc);
913 }
914
915 void wxShape::OnEraseContents(wxDC& dc)
916 {
917 if (!m_visible)
918 return;
919
920 float maxX, maxY, minX, minY;
921 float xp = GetX();
922 float yp = GetY();
923 GetBoundingBoxMin(&minX, &minY);
924 GetBoundingBoxMax(&maxX, &maxY);
925 float topLeftX = (float)(xp - (maxX / 2.0) - 2.0);
926 float topLeftY = (float)(yp - (maxY / 2.0) - 2.0);
927
928 int penWidth = 0;
929 if (m_pen)
930 penWidth = m_pen->GetWidth();
931
932 dc.SetPen(white_background_pen);
933 dc.SetBrush(white_background_brush);
934 dc.DrawRectangle((float)(topLeftX - penWidth), (float)(topLeftY - penWidth),
935 (float)(maxX + penWidth*2.0 + 4.0), (float)(maxY + penWidth*2.0 + 4.0));
936 }
937
938 void wxShape::EraseLinks(wxDC& dc, int attachment, bool recurse)
939 {
940 if (!m_visible)
941 return;
942
943 wxNode *current = m_lines.First();
944 while (current)
945 {
946 wxLineShape *line = (wxLineShape *)current->Data();
947 if (attachment == -1 || ((line->GetTo() == this && line->GetAttachmentTo() == attachment) ||
948 (line->GetFrom() == this && line->GetAttachmentFrom() == attachment)))
949 line->GetEventHandler()->OnErase(dc);
950 current = current->Next();
951 }
952 if (recurse)
953 {
954 wxNode *node = m_children.First();
955 while (node)
956 {
957 wxShape *child = (wxShape *)node->Data();
958 child->EraseLinks(dc, attachment, recurse);
959 node = node->Next();
960 }
961 }
962 }
963
964 void wxShape::DrawLinks(wxDC& dc, int attachment, bool recurse)
965 {
966 if (!m_visible)
967 return;
968
969 wxNode *current = m_lines.First();
970 while (current)
971 {
972 wxLineShape *line = (wxLineShape *)current->Data();
973 if (attachment == -1 ||
974 (line->GetTo() == this && line->GetAttachmentTo() == attachment) ||
975 (line->GetFrom() == this && line->GetAttachmentFrom() == attachment))
976 line->Draw(dc);
977 current = current->Next();
978 }
979 if (recurse)
980 {
981 wxNode *node = m_children.First();
982 while (node)
983 {
984 wxShape *child = (wxShape *)node->Data();
985 child->DrawLinks(dc, attachment, recurse);
986 node = node->Next();
987 }
988 }
989 }
990
991 void wxShape::MoveLineToNewAttachment(wxDC& dc, wxLineShape *to_move,
992 float x, float y)
993 {
994 int new_point;
995 float distance;
996
997 // Is (x, y) on this object? If so, find the new attachment point
998 // the user has moved the point to
999 bool hit = HitTest(x, y, &new_point, &distance);
1000 if (!hit)
1001 return;
1002
1003 EraseLinks(dc);
1004
1005 int old_attachment;
1006 if (to_move->GetTo() == this)
1007 old_attachment = to_move->GetAttachmentTo();
1008 else
1009 old_attachment = to_move->GetAttachmentFrom();
1010
1011 // Delete the line object from the list of links; we're going to move
1012 // it to another position in the list
1013 m_lines.DeleteObject(to_move);
1014
1015 float old_x = (float) -9999.9;
1016 float old_y = (float) -9999.9;
1017
1018 wxNode *node = m_lines.First();
1019 bool found = FALSE;
1020
1021 while (node && !found)
1022 {
1023 wxLineShape *line = (wxLineShape *)node->Data();
1024 if ((line->GetTo() == this && old_attachment == line->GetAttachmentTo()) ||
1025 (line->GetFrom() == this && old_attachment == line->GetAttachmentFrom()))
1026 {
1027 float startX, startY, endX, endY;
1028 float xp, yp;
1029 line->GetEnds(&startX, &startY, &endX, &endY);
1030 if (line->GetTo() == this)
1031 {
1032 // xp = line->m_xpos2 + line->m_xpos;
1033 // yp = line->m_ypos2 + line->m_ypos;
1034 xp = startX;
1035 yp = startY;
1036 } else
1037 {
1038 // xp = line->m_xpos1 + line->m_xpos;
1039 // yp = line->m_ypos1 + line->m_ypos;
1040 xp = endX;
1041 yp = endY;
1042 }
1043
1044 switch (old_attachment)
1045 {
1046 case 0:
1047 case 2:
1048 {
1049 if (x > old_x && x <= xp)
1050 {
1051 found = TRUE;
1052 m_lines.Insert(node, to_move);
1053 }
1054 break;
1055 }
1056 case 1:
1057 case 3:
1058 {
1059 if (y > old_y && y <= yp)
1060 {
1061 found = TRUE;
1062 m_lines.Insert(node, to_move);
1063 }
1064 break;
1065 }
1066 }
1067 old_x = xp;
1068 old_y = yp;
1069 }
1070 node = node->Next();
1071 }
1072 if (!found)
1073 m_lines.Append(to_move);
1074 }
1075
1076 // Reorders the lines coming into the node image at this attachment
1077 // position, in the order in which they appear in linesToSort.
1078 // Any remaining lines not in the list will be added to the end.
1079 void wxShape::SortLines(int attachment, wxList& linesToSort)
1080 {
1081 // This is a temporary store of all the lines at this attachment
1082 // point. We'll tick them off as we've processed them.
1083 wxList linesAtThisAttachment;
1084
1085 wxNode *node = m_lines.First();
1086 while (node)
1087 {
1088 wxLineShape *line = (wxLineShape *)node->Data();
1089 wxNode *next = node->Next();
1090 if ((line->GetTo() == this && line->GetAttachmentTo() == attachment) ||
1091 (line->GetFrom() == this && line->GetAttachmentFrom() == attachment))
1092 {
1093 linesAtThisAttachment.Append(line);
1094 delete node;
1095 node = next;
1096 }
1097 else node = node->Next();
1098 }
1099
1100 node = linesToSort.First();
1101 while (node)
1102 {
1103 wxLineShape *line = (wxLineShape *)node->Data();
1104 if (linesAtThisAttachment.Member(line))
1105 {
1106 // Done this one
1107 linesAtThisAttachment.DeleteObject(line);
1108 m_lines.Append(line);
1109 }
1110 node = node->Next();
1111 }
1112
1113 // Now add any lines that haven't been listed in linesToSort.
1114 node = linesAtThisAttachment.First();
1115 while (node)
1116 {
1117 wxLineShape *line = (wxLineShape *)node->Data();
1118 m_lines.Append(line);
1119 node = node->Next();
1120 }
1121 }
1122
1123 void wxShape::OnHighlight(wxDC& dc)
1124 {
1125 }
1126
1127 void wxShape::OnLeftClick(float x, float y, int keys, int attachment)
1128 {
1129 if ((m_sensitivity & OP_CLICK_LEFT) != OP_CLICK_LEFT)
1130 {
1131 attachment = 0;
1132 float dist;
1133 if (m_parent)
1134 {
1135 m_parent->HitTest(x, y, &attachment, &dist);
1136 m_parent->GetEventHandler()->OnLeftClick(x, y, keys, attachment);
1137 }
1138 return;
1139 }
1140 }
1141
1142 void wxShape::OnRightClick(float x, float y, int keys, int attachment)
1143 {
1144 if ((m_sensitivity & OP_CLICK_RIGHT) != OP_CLICK_RIGHT)
1145 {
1146 attachment = 0;
1147 float dist;
1148 if (m_parent)
1149 {
1150 m_parent->HitTest(x, y, &attachment, &dist);
1151 m_parent->GetEventHandler()->OnRightClick(x, y, keys, attachment);
1152 }
1153 return;
1154 }
1155 }
1156
1157 float DragOffsetX = 0.0;
1158 float DragOffsetY = 0.0;
1159
1160 void wxShape::OnDragLeft(bool draw, float x, float y, int keys, int attachment)
1161 {
1162 if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT)
1163 {
1164 attachment = 0;
1165 float dist;
1166 if (m_parent)
1167 {
1168 m_parent->HitTest(x, y, &attachment, &dist);
1169 m_parent->GetEventHandler()->OnDragLeft(draw, x, y, keys, attachment);
1170 }
1171 return;
1172 }
1173
1174 wxClientDC dc(GetCanvas());
1175 GetCanvas()->PrepareDC(dc);
1176
1177 dc.SetLogicalFunction(wxXOR);
1178
1179 wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
1180 dc.SetPen(dottedPen);
1181 dc.SetBrush(* wxTRANSPARENT_BRUSH);
1182
1183 float xx, yy;
1184 xx = x + DragOffsetX;
1185 yy = y + DragOffsetY;
1186
1187 m_canvas->Snap(&xx, &yy);
1188 // m_xpos = xx; m_ypos = yy;
1189 float w, h;
1190 GetBoundingBoxMax(&w, &h);
1191 GetEventHandler()->OnDrawOutline(dc, xx, yy, w, h);
1192 }
1193
1194 void wxShape::OnBeginDragLeft(float x, float y, int keys, int attachment)
1195 {
1196 if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT)
1197 {
1198 attachment = 0;
1199 float dist;
1200 if (m_parent)
1201 {
1202 m_parent->HitTest(x, y, &attachment, &dist);
1203 m_parent->GetEventHandler()->OnBeginDragLeft(x, y, keys, attachment);
1204 }
1205 return;
1206 }
1207
1208 DragOffsetX = m_xpos - x;
1209 DragOffsetY = m_ypos - y;
1210
1211 wxClientDC dc(GetCanvas());
1212 GetCanvas()->PrepareDC(dc);
1213
1214 Erase(dc);
1215 float xx, yy;
1216 xx = x + DragOffsetX;
1217 yy = y + DragOffsetY;
1218 m_canvas->Snap(&xx, &yy);
1219 // m_xpos = xx; m_ypos = yy;
1220 dc.SetLogicalFunction(wxXOR);
1221
1222 wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
1223 dc.SetPen(dottedPen);
1224 dc.SetBrush((* wxTRANSPARENT_BRUSH));
1225
1226 float w, h;
1227 GetBoundingBoxMax(&w, &h);
1228 GetEventHandler()->OnDrawOutline(dc, xx, yy, w, h);
1229 m_canvas->CaptureMouse();
1230 }
1231
1232 void wxShape::OnEndDragLeft(float x, float y, int keys, int attachment)
1233 {
1234 m_canvas->ReleaseMouse();
1235 if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT)
1236 {
1237 attachment = 0;
1238 float dist;
1239 if (m_parent)
1240 {
1241 m_parent->HitTest(x, y, &attachment, &dist);
1242 m_parent->GetEventHandler()->OnEndDragLeft(x, y, keys, attachment);
1243 }
1244 return;
1245 }
1246
1247 wxClientDC dc(GetCanvas());
1248 GetCanvas()->PrepareDC(dc);
1249
1250 dc.SetLogicalFunction(wxCOPY);
1251
1252 float xx = x + DragOffsetX;
1253 float yy = y + DragOffsetY;
1254 m_canvas->Snap(&xx, &yy);
1255 // canvas->Snap(&m_xpos, &m_ypos);
1256 Move(dc, xx, yy);
1257 if (m_canvas && !m_canvas->GetQuickEditMode()) m_canvas->Redraw(dc);
1258 }
1259
1260 void wxShape::OnDragRight(bool draw, float x, float y, int keys, int attachment)
1261 {
1262 if ((m_sensitivity & OP_DRAG_RIGHT) != OP_DRAG_RIGHT)
1263 {
1264 attachment = 0;
1265 float dist;
1266 if (m_parent)
1267 {
1268 m_parent->HitTest(x, y, &attachment, &dist);
1269 m_parent->GetEventHandler()->OnDragRight(draw, x, y, keys, attachment);
1270 }
1271 return;
1272 }
1273 }
1274
1275 void wxShape::OnBeginDragRight(float x, float y, int keys, int attachment)
1276 {
1277 if ((m_sensitivity & OP_DRAG_RIGHT) != OP_DRAG_RIGHT)
1278 {
1279 attachment = 0;
1280 float dist;
1281 if (m_parent)
1282 {
1283 m_parent->HitTest(x, y, &attachment, &dist);
1284 m_parent->GetEventHandler()->OnBeginDragRight(x, y, keys, attachment);
1285 }
1286 return;
1287 }
1288 }
1289
1290 void wxShape::OnEndDragRight(float x, float y, int keys, int attachment)
1291 {
1292 if ((m_sensitivity & OP_DRAG_RIGHT) != OP_DRAG_RIGHT)
1293 {
1294 attachment = 0;
1295 float dist;
1296 if (m_parent)
1297 {
1298 m_parent->HitTest(x, y, &attachment, &dist);
1299 m_parent->GetEventHandler()->OnEndDragRight(x, y, keys, attachment);
1300 }
1301 return;
1302 }
1303 }
1304
1305 void wxShape::OnDrawOutline(wxDC& dc, float x, float y, float w, float h)
1306 {
1307 float top_left_x = (float)(x - w/2.0);
1308 float top_left_y = (float)(y - h/2.0);
1309 float top_right_x = (float)(top_left_x + w);
1310 float top_right_y = (float)top_left_y;
1311 float bottom_left_x = (float)top_left_x;
1312 float bottom_left_y = (float)(top_left_y + h);
1313 float bottom_right_x = (float)top_right_x;
1314 float bottom_right_y = (float)bottom_left_y;
1315
1316 wxPoint points[5];
1317 points[0].x = top_left_x; points[0].y = top_left_y;
1318 points[1].x = top_right_x; points[1].y = top_right_y;
1319 points[2].x = bottom_right_x; points[2].y = bottom_right_y;
1320 points[3].x = bottom_left_x; points[3].y = bottom_left_y;
1321 points[4].x = top_left_x; points[4].y = top_left_y;
1322
1323 dc.DrawLines(5, points);
1324 }
1325
1326 void wxShape::Attach(wxShapeCanvas *can)
1327 {
1328 m_canvas = can;
1329 }
1330
1331 void wxShape::Detach()
1332 {
1333 m_canvas = NULL;
1334 }
1335
1336 void wxShape::Move(wxDC& dc, float x, float y, bool display)
1337 {
1338 float old_x = m_xpos;
1339 float old_y = m_ypos;
1340
1341 m_xpos = x; m_ypos = y;
1342
1343 if (!GetEventHandler()->OnMovePre(dc, x, y, old_x, old_y, display))
1344 {
1345 m_xpos = old_x;
1346 m_ypos = old_y;
1347 return;
1348 }
1349
1350 ResetControlPoints();
1351
1352 if (display)
1353 Draw(dc);
1354
1355 MoveLinks(dc);
1356
1357 GetEventHandler()->OnMovePost(dc, x, y, old_x, old_y, display);
1358 }
1359
1360 void wxShape::MoveLinks(wxDC& dc)
1361 {
1362 GetEventHandler()->OnMoveLinks(dc);
1363 }
1364
1365
1366 void wxShape::Draw(wxDC& dc)
1367 {
1368 if (m_visible)
1369 {
1370 GetEventHandler()->OnDraw(dc);
1371 GetEventHandler()->OnDrawContents(dc);
1372 GetEventHandler()->OnDrawControlPoints(dc);
1373 }
1374 }
1375
1376 void wxShape::Flash()
1377 {
1378 if (GetCanvas())
1379 {
1380 wxClientDC dc(GetCanvas());
1381 GetCanvas()->PrepareDC(dc);
1382
1383 dc.SetLogicalFunction(wxXOR);
1384 Draw(dc);
1385 dc.SetLogicalFunction(wxCOPY);
1386 Draw(dc);
1387 }
1388 }
1389
1390 void wxShape::Show(bool show)
1391 {
1392 m_visible = show;
1393 wxNode *node = m_children.First();
1394 while (node)
1395 {
1396 wxShape *image = (wxShape *)node->Data();
1397 image->Show(show);
1398 node = node->Next();
1399 }
1400 }
1401
1402 void wxShape::Erase(wxDC& dc)
1403 {
1404 GetEventHandler()->OnErase(dc);
1405 GetEventHandler()->OnEraseControlPoints(dc);
1406 }
1407
1408 void wxShape::EraseContents(wxDC& dc)
1409 {
1410 GetEventHandler()->OnEraseContents(dc);
1411 }
1412
1413 void wxShape::AddText(const wxString& string)
1414 {
1415 wxNode *node = m_regions.First();
1416 if (!node)
1417 return;
1418 wxShapeRegion *region = (wxShapeRegion *)node->Data();
1419 region->ClearText();
1420 wxShapeTextLine *new_line =
1421 new wxShapeTextLine(0.0, 0.0, string);
1422 region->GetFormattedText().Append(new_line);
1423
1424 m_formatted = FALSE;
1425 }
1426
1427 void wxShape::SetSize(float x, float y, bool recursive)
1428 {
1429 SetAttachmentSize(x, y);
1430 SetDefaultRegionSize();
1431 }
1432
1433 void wxShape::SetAttachmentSize(float w, float h)
1434 {
1435 float scaleX;
1436 float scaleY;
1437 float width, height;
1438 GetBoundingBoxMin(&width, &height);
1439 if (width == 0.0)
1440 scaleX = 1.0;
1441 else scaleX = w/width;
1442 if (height == 0.0)
1443 scaleY = 1.0;
1444 else scaleY = h/height;
1445
1446 wxNode *node = m_attachmentPoints.First();
1447 while (node)
1448 {
1449 wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
1450 point->m_x = (float)(point->m_x * scaleX);
1451 point->m_y = (float)(point->m_y * scaleY);
1452 node = node->Next();
1453 }
1454 }
1455
1456 // Add line FROM this object
1457 void wxShape::AddLine(wxLineShape *line, wxShape *other,
1458 int attachFrom, int attachTo)
1459 {
1460 if (!m_lines.Member(line))
1461 m_lines.Append(line);
1462
1463 if (!other->m_lines.Member(line))
1464 other->m_lines.Append(line);
1465
1466 line->SetFrom(this);
1467 line->SetTo(other);
1468 line->SetAttachments(attachFrom, attachTo);
1469 }
1470
1471 void wxShape::RemoveLine(wxLineShape *line)
1472 {
1473 if (line->GetFrom() == this)
1474 line->GetTo()->m_lines.DeleteObject(line);
1475 else
1476 line->GetFrom()->m_lines.DeleteObject(line);
1477
1478 m_lines.DeleteObject(line);
1479 }
1480
1481 #ifdef PROLOGIO
1482 char *wxShape::GetFunctor()
1483 {
1484 return "node_image";
1485 }
1486
1487 void wxShape::WritePrologAttributes(wxExpr *clause)
1488 {
1489 clause->AddAttributeValueString("type", GetClassInfo()->GetClassName());
1490 clause->AddAttributeValue("id", m_id);
1491
1492 if (m_pen)
1493 {
1494 int penWidth = m_pen->GetWidth();
1495 int penStyle = m_pen->GetStyle();
1496 if (penWidth != 1)
1497 clause->AddAttributeValue("pen_width", (long)penWidth);
1498 if (penStyle != wxSOLID)
1499 clause->AddAttributeValue("pen_style", (long)penStyle);
1500
1501 wxString penColour = wxTheColourDatabase->FindName(m_pen->GetColour());
1502 if ((penColour != "") && (penColour != "BLACK"))
1503 clause->AddAttributeValueString("pen_colour", penColour);
1504 }
1505
1506 if (m_brush)
1507 {
1508 wxString brushColour = wxTheColourDatabase->FindName(m_brush->GetColour());
1509
1510 if ((brushColour != "") && (brushColour != "WHITE"))
1511 clause->AddAttributeValueString("brush_colour", brushColour);
1512
1513 if (m_brush->GetStyle() != wxSOLID)
1514 clause->AddAttributeValue("brush_style", (long)m_brush->GetStyle());
1515 }
1516
1517 // Output line ids
1518
1519 int n_lines = m_lines.Number();
1520 if (n_lines > 0)
1521 {
1522 wxExpr *list = new wxExpr(PrologList);
1523 wxNode *node = m_lines.First();
1524 while (node)
1525 {
1526 wxShape *line = (wxShape *)node->Data();
1527 wxExpr *id_expr = new wxExpr(line->GetId());
1528 list->Append(id_expr);
1529 node = node->Next();
1530 }
1531 clause->AddAttributeValue("arcs", list);
1532 }
1533
1534 // Miscellaneous members
1535 if (m_attachmentMode != 0)
1536 clause->AddAttributeValue("use_attachments", (long)m_attachmentMode);
1537 if (m_sensitivity != OP_ALL)
1538 clause->AddAttributeValue("sensitivity", (long)m_sensitivity);
1539 if (!m_spaceAttachments)
1540 clause->AddAttributeValue("space_attachments", (long)m_spaceAttachments);
1541 if (m_fixedWidth)
1542 clause->AddAttributeValue("fixed_width", (long)m_fixedWidth);
1543 if (m_fixedHeight)
1544 clause->AddAttributeValue("fixed_height", (long)m_fixedHeight);
1545 if (m_shadowMode != SHADOW_NONE)
1546 clause->AddAttributeValue("shadow_mode", (long)m_shadowMode);
1547 if (m_centreResize != TRUE)
1548 clause->AddAttributeValue("centre_resize", (long)0);
1549 if (m_highlighted != FALSE)
1550 clause->AddAttributeValue("hilite", (long)m_highlighted);
1551
1552 if (m_parent) // For composite objects
1553 clause->AddAttributeValue("parent", (long)m_parent->GetId());
1554
1555 if (m_rotation != 0.0)
1556 clause->AddAttributeValue("rotation", m_rotation);
1557
1558 // Write user-defined attachment points, if any
1559 if (m_attachmentPoints.Number() > 0)
1560 {
1561 wxExpr *attachmentList = new wxExpr(PrologList);
1562 wxNode *node = m_attachmentPoints.First();
1563 while (node)
1564 {
1565 wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
1566 wxExpr *pointExpr = new wxExpr(PrologList);
1567 pointExpr->Append(new wxExpr((long)point->m_id));
1568 pointExpr->Append(new wxExpr(point->m_x));
1569 pointExpr->Append(new wxExpr(point->m_y));
1570 attachmentList->Append(pointExpr);
1571 node = node->Next();
1572 }
1573 clause->AddAttributeValue("user_attachments", attachmentList);
1574 }
1575
1576 // Write text regions
1577 WriteRegions(clause);
1578 }
1579
1580 void wxShape::WriteRegions(wxExpr *clause)
1581 {
1582 // Output regions as region1 = (...), region2 = (...), etc
1583 // and formatted text as text1 = (...), text2 = (...) etc.
1584 int regionNo = 1;
1585 char regionNameBuf[20];
1586 char textNameBuf[20];
1587 wxNode *node = m_regions.First();
1588 while (node)
1589 {
1590 wxShapeRegion *region = (wxShapeRegion *)node->Data();
1591 sprintf(regionNameBuf, "region%d", regionNo);
1592 sprintf(textNameBuf, "text%d", regionNo);
1593
1594 // Original text and region attributes:
1595 // region1 = (regionName regionText x y width height minWidth minHeight proportionX proportionY
1596 // formatMode fontSize fontFamily fontStyle fontWeight textColour)
1597 wxExpr *regionExpr = new wxExpr(PrologList);
1598 regionExpr->Append(new wxExpr(PrologString, (region->m_regionName ? region->m_regionName : "")));
1599 regionExpr->Append(new wxExpr(PrologString, (region->m_regionText ? region->m_regionText : "")));
1600
1601 regionExpr->Append(new wxExpr(region->m_x));
1602 regionExpr->Append(new wxExpr(region->m_y));
1603 regionExpr->Append(new wxExpr(region->GetWidth()));
1604 regionExpr->Append(new wxExpr(region->GetHeight()));
1605
1606 regionExpr->Append(new wxExpr(region->m_minWidth));
1607 regionExpr->Append(new wxExpr(region->m_minHeight));
1608 regionExpr->Append(new wxExpr(region->m_regionProportionX));
1609 regionExpr->Append(new wxExpr(region->m_regionProportionY));
1610
1611 regionExpr->Append(new wxExpr((long)region->m_formatMode));
1612
1613 regionExpr->Append(new wxExpr((long)(region->m_font ? region->m_font->GetPointSize() : 10)));
1614 regionExpr->Append(new wxExpr((long)(region->m_font ? region->m_font->GetFamily() : wxDEFAULT)));
1615 regionExpr->Append(new wxExpr((long)(region->m_font ? region->m_font->GetStyle() : wxDEFAULT)));
1616 regionExpr->Append(new wxExpr((long)(region->m_font ? region->m_font->GetWeight() : wxNORMAL)));
1617 regionExpr->Append(new wxExpr(PrologString, region->m_textColour ? region->m_textColour : "BLACK"));
1618
1619 // New members for pen colour/style
1620 regionExpr->Append(new wxExpr(PrologString, region->m_penColour ? region->m_penColour : "BLACK"));
1621 regionExpr->Append(new wxExpr((long)region->m_penStyle));
1622
1623 // Formatted text:
1624 // text1 = ((x y string) (x y string) ...)
1625 wxExpr *textExpr = new wxExpr(PrologList);
1626
1627 wxNode *textNode = region->m_formattedText.First();
1628 while (textNode)
1629 {
1630 wxShapeTextLine *line = (wxShapeTextLine *)textNode->Data();
1631 wxExpr *list2 = new wxExpr(PrologList);
1632 list2->Append(new wxExpr(line->GetX()));
1633 list2->Append(new wxExpr(line->GetY()));
1634 list2->Append(new wxExpr(PrologString, line->GetText()));
1635 textExpr->Append(list2);
1636 textNode = textNode->Next();
1637 }
1638
1639 // Now add both attributes to the clause
1640 clause->AddAttributeValue(regionNameBuf, regionExpr);
1641 clause->AddAttributeValue(textNameBuf, textExpr);
1642
1643 node = node->Next();
1644 regionNo ++;
1645 }
1646 }
1647
1648 void wxShape::ReadPrologAttributes(wxExpr *clause)
1649 {
1650 clause->GetAttributeValue("id", m_id);
1651 RegisterId(m_id);
1652
1653 clause->GetAttributeValue("x", m_xpos);
1654 clause->GetAttributeValue("y", m_ypos);
1655
1656 // Input text strings (FOR COMPATIBILITY WITH OLD FILES ONLY. SEE REGION CODE BELOW.)
1657 ClearText();
1658 wxExpr *strings = clause->AttributeValue("text");
1659 if (strings && strings->Type() == PrologList)
1660 {
1661 m_formatted = TRUE; // Assume text is formatted unless we prove otherwise
1662 wxExpr *node = strings->value.first;
1663 while (node)
1664 {
1665 wxExpr *string_expr = node;
1666 float the_x = 0.0;
1667 float the_y = 0.0;
1668 wxString the_string("");
1669
1670 // string_expr can either be a string, or a list of
1671 // 3 elements: x, y, and string.
1672 if (string_expr->Type() == PrologString)
1673 {
1674 the_string = string_expr->StringValue();
1675 m_formatted = FALSE;
1676 }
1677 else if (string_expr->Type() == PrologList)
1678 {
1679 wxExpr *first = string_expr->value.first;
1680 wxExpr *second = first ? first->next : NULL;
1681 wxExpr *third = second ? second->next : NULL;
1682
1683 if (first && second && third &&
1684 (first->Type() == PrologReal || first->Type() == PrologInteger) &&
1685 (second->Type() == PrologReal || second->Type() == PrologInteger) &&
1686 third->Type() == PrologString)
1687 {
1688 if (first->Type() == PrologReal)
1689 the_x = first->RealValue();
1690 else the_x = (float)first->IntegerValue();
1691
1692 if (second->Type() == PrologReal)
1693 the_y = second->RealValue();
1694 else the_y = (float)second->IntegerValue();
1695
1696 the_string = third->StringValue();
1697 }
1698 }
1699 wxShapeTextLine *line =
1700 new wxShapeTextLine(the_x, the_y, (char*) (const char*) the_string);
1701 m_text.Append(line);
1702
1703 node = node->next;
1704 }
1705 }
1706
1707 wxString pen_string = "";
1708 wxString brush_string = "";
1709 int pen_width = 1;
1710 int pen_style = wxSOLID;
1711 int brush_style = wxSOLID;
1712 m_attachmentMode = FALSE;
1713
1714 clause->GetAttributeValue("pen_colour", pen_string);
1715 clause->GetAttributeValue("text_colour", m_textColourName);
1716
1717 SetTextColour(m_textColourName);
1718
1719 clause->GetAttributeValue("region_name", m_regionName);
1720
1721 clause->GetAttributeValue("brush_colour", brush_string);
1722 clause->GetAttributeValue("pen_width", pen_width);
1723 clause->GetAttributeValue("pen_style", pen_style);
1724 clause->GetAttributeValue("brush_style", brush_style);
1725
1726 int iVal = (int) m_attachmentMode;
1727 clause->GetAttributeValue("use_attachments", iVal);
1728 m_attachmentMode = (iVal != 0);
1729
1730 clause->GetAttributeValue("sensitivity", m_sensitivity);
1731
1732 iVal = (int) m_spaceAttachments;
1733 clause->GetAttributeValue("space_attachments", iVal);
1734 m_spaceAttachments = (iVal != 0);
1735
1736 iVal = (int) m_fixedWidth;
1737 clause->GetAttributeValue("fixed_width", iVal);
1738 m_fixedWidth = (iVal != 0);
1739
1740 iVal = (int) m_fixedHeight;
1741 clause->GetAttributeValue("fixed_height", iVal);
1742 m_fixedHeight = (iVal != 0);
1743
1744 clause->GetAttributeValue("format_mode", m_formatMode);
1745 clause->GetAttributeValue("shadow_mode", m_shadowMode);
1746
1747 iVal = (int) m_centreResize;
1748 clause->GetAttributeValue("centre_resize", iVal);
1749 m_centreResize = (iVal != 0);
1750
1751 iVal = (int) m_highlighted;
1752 clause->GetAttributeValue("hilite", iVal);
1753 m_highlighted = (iVal != 0);
1754
1755 clause->GetAttributeValue("rotation", m_rotation);
1756
1757 if (pen_string == "")
1758 pen_string = "BLACK";
1759 if (brush_string == "")
1760 brush_string = "WHITE";
1761
1762 m_pen = wxThePenList->FindOrCreatePen(pen_string, pen_width, pen_style);
1763 if (!m_pen)
1764 m_pen = wxBLACK_PEN;
1765
1766 m_brush = wxTheBrushList->FindOrCreateBrush(brush_string, brush_style);
1767 if (!m_brush)
1768 m_brush = wxWHITE_BRUSH;
1769
1770 int point_size = 10;
1771 clause->GetAttributeValue("point_size", point_size);
1772 SetFont(MatchFont(point_size));
1773
1774 // Read user-defined attachment points, if any
1775 wxExpr *attachmentList = clause->AttributeValue("user_attachments");
1776 if (attachmentList)
1777 {
1778 wxExpr *pointExpr = attachmentList->GetFirst();
1779 while (pointExpr)
1780 {
1781 wxExpr *idExpr = pointExpr->Nth(0);
1782 wxExpr *xExpr = pointExpr->Nth(1);
1783 wxExpr *yExpr = pointExpr->Nth(2);
1784 if (idExpr && xExpr && yExpr)
1785 {
1786 wxAttachmentPoint *point = new wxAttachmentPoint;
1787 point->m_id = (int)idExpr->IntegerValue();
1788 point->m_x = xExpr->RealValue();
1789 point->m_y = yExpr->RealValue();
1790 m_attachmentPoints.Append((wxObject *)point);
1791 }
1792 pointExpr = pointExpr->GetNext();
1793 }
1794 }
1795
1796 // Read text regions
1797 ReadRegions(clause);
1798 }
1799
1800 void wxShape::ReadRegions(wxExpr *clause)
1801 {
1802 ClearRegions();
1803
1804 // region1 = (regionName regionText x y width height minWidth minHeight proportionX proportionY
1805 // formatMode fontSize fontFamily fontStyle fontWeight textColour)
1806 int regionNo = 1;
1807 char regionNameBuf[20];
1808 char textNameBuf[20];
1809
1810 wxExpr *regionExpr = NULL;
1811 wxExpr *textExpr = NULL;
1812 sprintf(regionNameBuf, "region%d", regionNo);
1813 sprintf(textNameBuf, "text%d", regionNo);
1814
1815 m_formatted = TRUE; // Assume text is formatted unless we prove otherwise
1816
1817 while (regionExpr = clause->AttributeValue(regionNameBuf))
1818 {
1819 /*
1820 * Get the region information
1821 *
1822 */
1823
1824 wxString regionName("");
1825 wxString regionText("");
1826 float x = 0.0;
1827 float y = 0.0;
1828 float width = 0.0;
1829 float height = 0.0;
1830 float minWidth = 5.0;
1831 float minHeight = 5.0;
1832 float m_regionProportionX = -1.0;
1833 float m_regionProportionY = -1.0;
1834 int formatMode = FORMAT_NONE;
1835 int fontSize = 10;
1836 int fontFamily = wxSWISS;
1837 int fontStyle = wxNORMAL;
1838 int fontWeight = wxNORMAL;
1839 wxString regionTextColour("");
1840 wxString penColour("");
1841 int penStyle = wxSOLID;
1842
1843 if (regionExpr->Type() == PrologList)
1844 {
1845 wxExpr *nameExpr = regionExpr->Nth(0);
1846 wxExpr *textExpr = regionExpr->Nth(1);
1847 wxExpr *xExpr = regionExpr->Nth(2);
1848 wxExpr *yExpr = regionExpr->Nth(3);
1849 wxExpr *widthExpr = regionExpr->Nth(4);
1850 wxExpr *heightExpr = regionExpr->Nth(5);
1851 wxExpr *minWidthExpr = regionExpr->Nth(6);
1852 wxExpr *minHeightExpr = regionExpr->Nth(7);
1853 wxExpr *propXExpr = regionExpr->Nth(8);
1854 wxExpr *propYExpr = regionExpr->Nth(9);
1855 wxExpr *formatExpr = regionExpr->Nth(10);
1856 wxExpr *sizeExpr = regionExpr->Nth(11);
1857 wxExpr *familyExpr = regionExpr->Nth(12);
1858 wxExpr *styleExpr = regionExpr->Nth(13);
1859 wxExpr *weightExpr = regionExpr->Nth(14);
1860 wxExpr *colourExpr = regionExpr->Nth(15);
1861 wxExpr *penColourExpr = regionExpr->Nth(16);
1862 wxExpr *penStyleExpr = regionExpr->Nth(17);
1863
1864 regionName = nameExpr->StringValue();
1865 regionText = textExpr->StringValue();
1866
1867 x = xExpr->RealValue();
1868 y = yExpr->RealValue();
1869
1870 width = widthExpr->RealValue();
1871 height = heightExpr->RealValue();
1872
1873 minWidth = minWidthExpr->RealValue();
1874 minHeight = minHeightExpr->RealValue();
1875
1876 m_regionProportionX = propXExpr->RealValue();
1877 m_regionProportionY = propYExpr->RealValue();
1878
1879 formatMode = (formatExpr->IntegerValue() != 0);
1880 fontSize = (int)sizeExpr->IntegerValue();
1881 fontFamily = (int)familyExpr->IntegerValue();
1882 fontStyle = (int)styleExpr->IntegerValue();
1883 fontWeight = (int)weightExpr->IntegerValue();
1884
1885 if (colourExpr)
1886 {
1887 regionTextColour = colourExpr->StringValue();
1888 }
1889 else
1890 regionTextColour = "BLACK";
1891
1892 if (penColourExpr)
1893 penColour = penColourExpr->StringValue();
1894 if (penStyleExpr)
1895 penStyle = (int)penStyleExpr->IntegerValue();
1896 }
1897 wxFont *font = wxTheFontList->FindOrCreateFont(fontSize, fontFamily, fontStyle, fontWeight);
1898
1899 wxShapeRegion *region = new wxShapeRegion;
1900 region->SetProportions(m_regionProportionX, m_regionProportionY);
1901 region->SetFont(font);
1902 region->SetSize(width, height);
1903 region->SetPosition(x, y);
1904 region->SetMinSize(minWidth, minHeight);
1905 region->SetFormatMode(formatMode);
1906 region->SetPenStyle(penStyle);
1907 if (penColour != "")
1908 region->SetPenColour(penColour);
1909
1910 region->m_textColour = regionTextColour;
1911 region->m_regionText = regionText;
1912 region->m_regionName = regionName;
1913
1914 m_regions.Append(region);
1915
1916 /*
1917 * Get the formatted text strings
1918 *
1919 */
1920 textExpr = clause->AttributeValue(textNameBuf);
1921 if (textExpr && (textExpr->Type() == PrologList))
1922 {
1923 wxExpr *node = textExpr->value.first;
1924 while (node)
1925 {
1926 wxExpr *string_expr = node;
1927 float the_x = 0.0;
1928 float the_y = 0.0;
1929 wxString the_string("");
1930
1931 // string_expr can either be a string, or a list of
1932 // 3 elements: x, y, and string.
1933 if (string_expr->Type() == PrologString)
1934 {
1935 the_string = string_expr->StringValue();
1936 m_formatted = FALSE;
1937 }
1938 else if (string_expr->Type() == PrologList)
1939 {
1940 wxExpr *first = string_expr->value.first;
1941 wxExpr *second = first ? first->next : NULL;
1942 wxExpr *third = second ? second->next : NULL;
1943
1944 if (first && second && third &&
1945 (first->Type() == PrologReal || first->Type() == PrologInteger) &&
1946 (second->Type() == PrologReal || second->Type() == PrologInteger) &&
1947 third->Type() == PrologString)
1948 {
1949 if (first->Type() == PrologReal)
1950 the_x = first->RealValue();
1951 else the_x = (float)first->IntegerValue();
1952
1953 if (second->Type() == PrologReal)
1954 the_y = second->RealValue();
1955 else the_y = (float)second->IntegerValue();
1956
1957 the_string = third->StringValue();
1958 }
1959 }
1960 if (the_string)
1961 {
1962 wxShapeTextLine *line =
1963 new wxShapeTextLine(the_x, the_y, (char*) (const char*) the_string);
1964 region->m_formattedText.Append(line);
1965 }
1966 node = node->next;
1967 }
1968 }
1969
1970 regionNo ++;
1971 sprintf(regionNameBuf, "region%d", regionNo);
1972 sprintf(textNameBuf, "text%d", regionNo);
1973 }
1974
1975 // Compatibility: check for no regions (old file).
1976 // Lines and divided rectangles must deal with this compatibility
1977 // theirselves. Composites _may_ not have any regions anyway.
1978 if ((m_regions.Number() == 0) &&
1979 !this->IsKindOf(CLASSINFO(wxLineShape)) && !this->IsKindOf(CLASSINFO(wxDividedShape)) &&
1980 !this->IsKindOf(CLASSINFO(wxCompositeShape)))
1981 {
1982 wxShapeRegion *newRegion = new wxShapeRegion;
1983 newRegion->SetName("0");
1984 m_regions.Append((wxObject *)newRegion);
1985 if (m_text.Number() > 0)
1986 {
1987 newRegion->ClearText();
1988 wxNode *node = m_text.First();
1989 while (node)
1990 {
1991 wxShapeTextLine *textLine = (wxShapeTextLine *)node->Data();
1992 wxNode *next = node->Next();
1993 newRegion->GetFormattedText().Append((wxObject *)textLine);
1994 delete node;
1995 node = next;
1996 }
1997 }
1998 }
1999 }
2000
2001 #endif
2002
2003 void wxShape::Copy(wxShape& copy)
2004 {
2005 copy.m_xpos = m_xpos;
2006 copy.m_ypos = m_ypos;
2007 copy.m_pen = m_pen;
2008 copy.m_brush = m_brush;
2009 copy.m_textColour = m_textColour;
2010 copy.m_centreResize = m_centreResize;
2011 copy.m_attachmentMode = m_attachmentMode;
2012 copy.m_spaceAttachments = m_spaceAttachments;
2013 copy.m_highlighted = m_highlighted;
2014 copy.m_rotation = m_rotation;
2015 copy.m_textColourName = m_textColourName;
2016 copy.m_regionName = m_regionName;
2017
2018 copy.m_sensitivity = m_sensitivity;
2019 copy.m_draggable = m_draggable;
2020 copy.m_fixedWidth = m_fixedWidth;
2021 copy.m_fixedHeight = m_fixedHeight;
2022 copy.m_formatMode = m_formatMode;
2023 copy.m_drawHandles = m_drawHandles;
2024
2025 copy.m_visible = m_visible;
2026 copy.m_shadowMode = m_shadowMode;
2027 copy.m_shadowOffsetX = m_shadowOffsetX;
2028 copy.m_shadowOffsetY = m_shadowOffsetY;
2029 copy.m_shadowBrush = m_shadowBrush;
2030
2031 // Copy text regions
2032 copy.ClearRegions();
2033 wxNode *node = m_regions.First();
2034 while (node)
2035 {
2036 wxShapeRegion *region = (wxShapeRegion *)node->Data();
2037 wxShapeRegion *newRegion = new wxShapeRegion(*region);
2038 copy.m_regions.Append(newRegion);
2039 node = node->Next();
2040 }
2041
2042 // Copy attachments
2043 copy.ClearAttachments();
2044 node = m_attachmentPoints.First();
2045 while (node)
2046 {
2047 wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
2048 wxAttachmentPoint *newPoint = new wxAttachmentPoint;
2049 newPoint->m_id = point->m_id;
2050 newPoint->m_x = point->m_x;
2051 newPoint->m_y = point->m_y;
2052 copy.m_attachmentPoints.Append((wxObject *)newPoint);
2053 node = node->Next();
2054 }
2055 }
2056
2057 // Create and return a new, fully copied object.
2058 wxShape *wxShape::CreateNewCopy(wxShapeCanvas *theCanvas)
2059 {
2060 wxObjectCopyMapping.Clear();
2061 wxShape *newObject = PrivateCopy();
2062 if (theCanvas)
2063 newObject->AddToCanvas(theCanvas);
2064 newObject->Recompute();
2065 return newObject;
2066 }
2067
2068 // Default - make 6 control points
2069 void wxShape::MakeControlPoints()
2070 {
2071 float maxX, maxY, minX, minY;
2072
2073 GetBoundingBoxMax(&maxX, &maxY);
2074 GetBoundingBoxMin(&minX, &minY);
2075
2076 float widthMin = (float)(minX + CONTROL_POINT_SIZE + 2);
2077 float heightMin = (float)(minY + CONTROL_POINT_SIZE + 2);
2078
2079 // Offsets from main object
2080 float top = (float)(- (heightMin / 2.0));
2081 float bottom = (float)(heightMin / 2.0 + (maxY - minY));
2082 float left = (float)(- (widthMin / 2.0));
2083 float right = (float)(widthMin / 2.0 + (maxX - minX));
2084
2085 wxControlPoint *control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, top,
2086 CONTROL_POINT_DIAGONAL);
2087 m_canvas->AddShape(control);
2088 m_controlPoints.Append(control);
2089
2090 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, 0, top,
2091 CONTROL_POINT_VERTICAL);
2092 m_canvas->AddShape(control);
2093 m_controlPoints.Append(control);
2094
2095 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, top,
2096 CONTROL_POINT_DIAGONAL);
2097 m_canvas->AddShape(control);
2098 m_controlPoints.Append(control);
2099
2100 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, 0,
2101 CONTROL_POINT_HORIZONTAL);
2102 m_canvas->AddShape(control);
2103 m_controlPoints.Append(control);
2104
2105 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, bottom,
2106 CONTROL_POINT_DIAGONAL);
2107 m_canvas->AddShape(control);
2108 m_controlPoints.Append(control);
2109
2110 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, 0, bottom,
2111 CONTROL_POINT_VERTICAL);
2112 m_canvas->AddShape(control);
2113 m_controlPoints.Append(control);
2114
2115 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, bottom,
2116 CONTROL_POINT_DIAGONAL);
2117 m_canvas->AddShape(control);
2118 m_controlPoints.Append(control);
2119
2120 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, 0,
2121 CONTROL_POINT_HORIZONTAL);
2122 m_canvas->AddShape(control);
2123 m_controlPoints.Append(control);
2124
2125 }
2126
2127 void wxShape::MakeMandatoryControlPoints()
2128 {
2129 wxNode *node = m_children.First();
2130 while (node)
2131 {
2132 wxShape *child = (wxShape *)node->Data();
2133 child->MakeMandatoryControlPoints();
2134 node = node->Next();
2135 }
2136 }
2137
2138 void wxShape::ResetMandatoryControlPoints()
2139 {
2140 wxNode *node = m_children.First();
2141 while (node)
2142 {
2143 wxShape *child = (wxShape *)node->Data();
2144 child->ResetMandatoryControlPoints();
2145 node = node->Next();
2146 }
2147 }
2148
2149 void wxShape::ResetControlPoints()
2150 {
2151 ResetMandatoryControlPoints();
2152
2153 if (m_controlPoints.Number() < 1)
2154 return;
2155
2156 float maxX, maxY, minX, minY;
2157
2158 GetBoundingBoxMax(&maxX, &maxY);
2159 GetBoundingBoxMin(&minX, &minY);
2160
2161 float widthMin = (float)(minX + CONTROL_POINT_SIZE + 2);
2162 float heightMin = (float)(minY + CONTROL_POINT_SIZE + 2);
2163
2164 // Offsets from main object
2165 float top = (float)(- (heightMin / 2.0));
2166 float bottom = (float)(heightMin / 2.0 + (maxY - minY));
2167 float left = (float)(- (widthMin / 2.0));
2168 float right = (float)(widthMin / 2.0 + (maxX - minX));
2169
2170 wxNode *node = m_controlPoints.First();
2171 wxControlPoint *control = (wxControlPoint *)node->Data();
2172 control->m_xoffset = left; control->m_yoffset = top;
2173
2174 node = node->Next(); control = (wxControlPoint *)node->Data();
2175 control->m_xoffset = 0; control->m_yoffset = top;
2176
2177 node = node->Next(); control = (wxControlPoint *)node->Data();
2178 control->m_xoffset = right; control->m_yoffset = top;
2179
2180 node = node->Next(); control = (wxControlPoint *)node->Data();
2181 control->m_xoffset = right; control->m_yoffset = 0;
2182
2183 node = node->Next(); control = (wxControlPoint *)node->Data();
2184 control->m_xoffset = right; control->m_yoffset = bottom;
2185
2186 node = node->Next(); control = (wxControlPoint *)node->Data();
2187 control->m_xoffset = 0; control->m_yoffset = bottom;
2188
2189 node = node->Next(); control = (wxControlPoint *)node->Data();
2190 control->m_xoffset = left; control->m_yoffset = bottom;
2191
2192 node = node->Next(); control = (wxControlPoint *)node->Data();
2193 control->m_xoffset = left; control->m_yoffset = 0;
2194 }
2195
2196 void wxShape::DeleteControlPoints(wxDC *dc)
2197 {
2198 wxNode *node = m_controlPoints.First();
2199 while (node)
2200 {
2201 wxControlPoint *control = (wxControlPoint *)node->Data();
2202 if (dc)
2203 control->GetEventHandler()->OnErase(*dc);
2204 m_canvas->RemoveShape(control);
2205 delete control;
2206 delete node;
2207 node = m_controlPoints.First();
2208 }
2209 // Children of divisions are contained objects,
2210 // so stop here
2211 if (!IsKindOf(CLASSINFO(wxDivisionShape)))
2212 {
2213 node = m_children.First();
2214 while (node)
2215 {
2216 wxShape *child = (wxShape *)node->Data();
2217 child->DeleteControlPoints(dc);
2218 node = node->Next();
2219 }
2220 }
2221 }
2222
2223 void wxShape::OnDrawControlPoints(wxDC& dc)
2224 {
2225 if (!m_drawHandles)
2226 return;
2227
2228 dc.SetBrush(wxBLACK_BRUSH);
2229 dc.SetPen(wxBLACK_PEN);
2230
2231 wxNode *node = m_controlPoints.First();
2232 while (node)
2233 {
2234 wxControlPoint *control = (wxControlPoint *)node->Data();
2235 control->Draw(dc);
2236 node = node->Next();
2237 }
2238 // Children of divisions are contained objects,
2239 // so stop here.
2240 // This test bypasses the type facility for speed
2241 // (critical when drawing)
2242 if (!IsKindOf(CLASSINFO(wxDivisionShape)))
2243 {
2244 node = m_children.First();
2245 while (node)
2246 {
2247 wxShape *child = (wxShape *)node->Data();
2248 child->GetEventHandler()->OnDrawControlPoints(dc);
2249 node = node->Next();
2250 }
2251 }
2252 }
2253
2254 void wxShape::OnEraseControlPoints(wxDC& dc)
2255 {
2256 wxNode *node = m_controlPoints.First();
2257 while (node)
2258 {
2259 wxControlPoint *control = (wxControlPoint *)node->Data();
2260 control->Erase(dc);
2261 node = node->Next();
2262 }
2263 if (!IsKindOf(CLASSINFO(wxDivisionShape)))
2264 {
2265 node = m_children.First();
2266 while (node)
2267 {
2268 wxShape *child = (wxShape *)node->Data();
2269 child->GetEventHandler()->OnEraseControlPoints(dc);
2270 node = node->Next();
2271 }
2272 }
2273 }
2274
2275 void wxShape::Select(bool select, wxDC* dc)
2276 {
2277 m_selected = select;
2278 if (select)
2279 {
2280 MakeControlPoints();
2281 // Children of divisions are contained objects,
2282 // so stop here
2283 if (!IsKindOf(CLASSINFO(wxDivisionShape)))
2284 {
2285 wxNode *node = m_children.First();
2286 while (node)
2287 {
2288 wxShape *child = (wxShape *)node->Data();
2289 child->MakeMandatoryControlPoints();
2290 node = node->Next();
2291 }
2292 }
2293 if (dc)
2294 GetEventHandler()->OnDrawControlPoints(*dc);
2295 }
2296 if (!select)
2297 {
2298 DeleteControlPoints(dc);
2299 if (!IsKindOf(CLASSINFO(wxDivisionShape)))
2300 {
2301 wxNode *node = m_children.First();
2302 while (node)
2303 {
2304 wxShape *child = (wxShape *)node->Data();
2305 child->DeleteControlPoints(dc);
2306 node = node->Next();
2307 }
2308 }
2309 }
2310 }
2311
2312 bool wxShape::Selected() const
2313 {
2314 return m_selected;
2315 }
2316
2317 bool wxShape::AncestorSelected() const
2318 {
2319 if (m_selected) return TRUE;
2320 if (!GetParent())
2321 return FALSE;
2322 else
2323 return GetParent()->AncestorSelected();
2324 }
2325
2326 int wxShape::GetNumberOfAttachments()
2327 {
2328 // Should return the MAXIMUM attachment point id here,
2329 // so higher-level functions can iterate through all attachments,
2330 // even if they're not contiguous.
2331 if (m_attachmentPoints.Number() == 0)
2332 return 4;
2333 else
2334 {
2335 int maxN = 3;
2336 wxNode *node = m_attachmentPoints.First();
2337 while (node)
2338 {
2339 wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
2340 if (point->m_id > maxN)
2341 maxN = point->m_id;
2342 node = node->Next();
2343 }
2344 return maxN+1;;
2345 }
2346 }
2347
2348 bool wxShape::AttachmentIsValid(int attachment)
2349 {
2350 if ((attachment >= 0) && (attachment < 4))
2351 return TRUE;
2352
2353 wxNode *node = m_attachmentPoints.First();
2354 while (node)
2355 {
2356 wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
2357 if (point->m_id == attachment)
2358 return TRUE;
2359 node = node->Next();
2360 }
2361 return FALSE;
2362 }
2363
2364 bool wxShape::GetAttachmentPosition(int attachment, float *x, float *y,
2365 int nth, int no_arcs, wxLineShape *line)
2366 {
2367 if (!m_attachmentMode)
2368 {
2369 *x = m_xpos; *y = m_ypos;
2370 return TRUE;
2371 }
2372 else
2373 {
2374 wxNode *node = m_attachmentPoints.First();
2375 while (node)
2376 {
2377 wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
2378 if (point->m_id == attachment)
2379 {
2380 *x = (float)(m_xpos + point->m_x);
2381 *y = (float)(m_ypos + point->m_y);
2382 return TRUE;
2383 }
2384 node = node->Next();
2385 }
2386 *x = m_xpos; *y = m_ypos;
2387 return FALSE;
2388 }
2389 }
2390
2391 void wxShape::GetBoundingBoxMax(float *w, float *h)
2392 {
2393 float ww, hh;
2394 GetBoundingBoxMin(&ww, &hh);
2395 if (m_shadowMode != SHADOW_NONE)
2396 {
2397 ww += m_shadowOffsetX;
2398 hh += m_shadowOffsetY;
2399 }
2400 *w = ww;
2401 *h = hh;
2402 }
2403
2404 // Returns TRUE if image is a descendant of this composite
2405 bool wxShape::HasDescendant(wxShape *image)
2406 {
2407 if (image == this)
2408 return TRUE;
2409 wxNode *node = m_children.First();
2410 while (node)
2411 {
2412 wxShape *child = (wxShape *)node->Data();
2413 bool ans = child->HasDescendant(image);
2414 if (ans)
2415 return TRUE;
2416 node = node->Next();
2417 }
2418 return FALSE;
2419 }
2420
2421 // Clears points from a list of wxRealPoints, and clears list
2422 void wxShape::ClearPointList(wxList& list)
2423 {
2424 wxNode* node = list.First();
2425 while (node)
2426 {
2427 wxRealPoint* pt = (wxRealPoint*) node->Data();
2428 delete pt;
2429
2430 node = node->Next();
2431 }
2432 list.Clear();
2433 }
2434