]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/ogl/basic.cpp
Fixes to BC++ compilation in mem debug mode
[wxWidgets.git] / contrib / src / ogl / 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 #include <wx/wxexpr.h>
28
29 #ifdef new
30 #undef new
31 #endif
32
33 #if wxUSE_IOSTREAMH
34 #include <iostream.h>
35 #else
36 #include <iostream>
37 #endif
38
39 #include <stdio.h>
40 #include <ctype.h>
41 #include <math.h>
42
43 #include <wx/ogl/basic.h>
44 #include <wx/ogl/basicp.h>
45 #include <wx/ogl/composit.h>
46 #include <wx/ogl/lines.h>
47 #include <wx/ogl/canvas.h>
48 #include <wx/ogl/divided.h>
49 #include <wx/ogl/misc.h>
50
51 // Control point types
52 // Rectangle and most other shapes
53 #define CONTROL_POINT_VERTICAL 1
54 #define CONTROL_POINT_HORIZONTAL 2
55 #define CONTROL_POINT_DIAGONAL 3
56
57 // Line
58 #define CONTROL_POINT_ENDPOINT_TO 4
59 #define CONTROL_POINT_ENDPOINT_FROM 5
60 #define CONTROL_POINT_LINE 6
61
62 IMPLEMENT_DYNAMIC_CLASS(wxShapeTextLine, wxObject)
63 IMPLEMENT_DYNAMIC_CLASS(wxAttachmentPoint, wxObject)
64
65 wxShapeTextLine::wxShapeTextLine(double the_x, double the_y, const wxString& the_line)
66 {
67 m_x = the_x; m_y = the_y; m_line = the_line;
68 }
69
70 wxShapeTextLine::~wxShapeTextLine()
71 {
72 }
73
74 IMPLEMENT_ABSTRACT_CLASS(wxShapeEvtHandler, wxObject)
75
76 wxShapeEvtHandler::wxShapeEvtHandler(wxShapeEvtHandler *prev, wxShape *shape)
77 {
78 m_previousHandler = prev;
79 m_handlerShape = shape;
80 }
81
82 wxShapeEvtHandler::~wxShapeEvtHandler()
83 {
84 }
85
86 // Creates a copy of this event handler.
87 wxShapeEvtHandler* wxShapeEvtHandler::CreateNewCopy()
88 {
89 wxShapeEvtHandler* newObject = (wxShapeEvtHandler*) GetClassInfo()->CreateObject();
90
91 wxASSERT( (newObject != NULL) );
92 wxASSERT( (newObject->IsKindOf(CLASSINFO(wxShapeEvtHandler))) );
93
94 newObject->m_previousHandler = newObject;
95
96 CopyData(*newObject);
97
98 return newObject;
99 }
100
101
102 void wxShapeEvtHandler::OnDelete()
103 {
104 if (this != GetShape())
105 delete this;
106 }
107
108 void wxShapeEvtHandler::OnDraw(wxDC& dc)
109 {
110 if (m_previousHandler)
111 m_previousHandler->OnDraw(dc);
112 }
113
114 void wxShapeEvtHandler::OnMoveLinks(wxDC& dc)
115 {
116 if (m_previousHandler)
117 m_previousHandler->OnMoveLinks(dc);
118 }
119
120 void wxShapeEvtHandler::OnMoveLink(wxDC& dc, bool moveControlPoints)
121 {
122 if (m_previousHandler)
123 m_previousHandler->OnMoveLink(dc, moveControlPoints);
124 }
125
126 void wxShapeEvtHandler::OnDrawContents(wxDC& dc)
127 {
128 if (m_previousHandler)
129 m_previousHandler->OnDrawContents(dc);
130 }
131
132 void wxShapeEvtHandler::OnDrawBranches(wxDC& dc, bool erase)
133 {
134 if (m_previousHandler)
135 m_previousHandler->OnDrawBranches(dc, erase);
136 }
137
138 void wxShapeEvtHandler::OnSize(double x, double y)
139 {
140 if (m_previousHandler)
141 m_previousHandler->OnSize(x, y);
142 }
143
144 bool wxShapeEvtHandler::OnMovePre(wxDC& dc, double x, double y, double old_x, double old_y, bool display)
145 {
146 if (m_previousHandler)
147 return m_previousHandler->OnMovePre(dc, x, y, old_x, old_y, display);
148 else
149 return TRUE;
150 }
151
152 void wxShapeEvtHandler::OnMovePost(wxDC& dc, double x, double y, double old_x, double old_y, bool display)
153 {
154 if (m_previousHandler)
155 m_previousHandler->OnMovePost(dc, x, y, old_x, old_y, display);
156 }
157
158 void wxShapeEvtHandler::OnErase(wxDC& dc)
159 {
160 if (m_previousHandler)
161 m_previousHandler->OnErase(dc);
162 }
163
164 void wxShapeEvtHandler::OnEraseContents(wxDC& dc)
165 {
166 if (m_previousHandler)
167 m_previousHandler->OnEraseContents(dc);
168 }
169
170 void wxShapeEvtHandler::OnHighlight(wxDC& dc)
171 {
172 if (m_previousHandler)
173 m_previousHandler->OnHighlight(dc);
174 }
175
176 void wxShapeEvtHandler::OnLeftClick(double x, double y, int keys, int attachment)
177 {
178 if (m_previousHandler)
179 m_previousHandler->OnLeftClick(x, y, keys, attachment);
180 }
181
182 void wxShapeEvtHandler::OnLeftDoubleClick(double x, double y, int keys, int attachment)
183 {
184 if (m_previousHandler)
185 m_previousHandler->OnLeftDoubleClick(x, y, keys, attachment);
186 }
187
188 void wxShapeEvtHandler::OnRightClick(double x, double y, int keys, int attachment)
189 {
190 if (m_previousHandler)
191 m_previousHandler->OnRightClick(x, y, keys, attachment);
192 }
193
194 void wxShapeEvtHandler::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
195 {
196 if (m_previousHandler)
197 m_previousHandler->OnDragLeft(draw, x, y, keys, attachment);
198 }
199
200 void wxShapeEvtHandler::OnBeginDragLeft(double x, double y, int keys, int attachment)
201 {
202 if (m_previousHandler)
203 m_previousHandler->OnBeginDragLeft(x, y, keys, attachment);
204 }
205
206 void wxShapeEvtHandler::OnEndDragLeft(double x, double y, int keys, int attachment)
207 {
208 if (m_previousHandler)
209 m_previousHandler->OnEndDragLeft(x, y, keys, attachment);
210 }
211
212 void wxShapeEvtHandler::OnDragRight(bool draw, double x, double y, int keys, int attachment)
213 {
214 if (m_previousHandler)
215 m_previousHandler->OnDragRight(draw, x, y, keys, attachment);
216 }
217
218 void wxShapeEvtHandler::OnBeginDragRight(double x, double y, int keys, int attachment)
219 {
220 if (m_previousHandler)
221 m_previousHandler->OnBeginDragRight(x, y, keys, attachment);
222 }
223
224 void wxShapeEvtHandler::OnEndDragRight(double x, double y, int keys, int attachment)
225 {
226 if (m_previousHandler)
227 m_previousHandler->OnEndDragRight(x, y, keys, attachment);
228 }
229
230 // Control points ('handles') redirect control to the actual shape, to make it easier
231 // to override sizing behaviour.
232 void wxShapeEvtHandler::OnSizingDragLeft(wxControlPoint* pt, bool draw, double x, double y, int keys, int attachment)
233 {
234 if (m_previousHandler)
235 m_previousHandler->OnSizingDragLeft(pt, draw, x, y, keys, attachment);
236 }
237
238 void wxShapeEvtHandler::OnSizingBeginDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment)
239 {
240 if (m_previousHandler)
241 m_previousHandler->OnSizingBeginDragLeft(pt, x, y, keys, attachment);
242 }
243
244 void wxShapeEvtHandler::OnSizingEndDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment)
245 {
246 if (m_previousHandler)
247 m_previousHandler->OnSizingEndDragLeft(pt, x, y, keys, attachment);
248 }
249
250 void wxShapeEvtHandler::OnDrawOutline(wxDC& dc, double x, double y, double w, double h)
251 {
252 if (m_previousHandler)
253 m_previousHandler->OnDrawOutline(dc, x, y, w, h);
254 }
255
256 void wxShapeEvtHandler::OnDrawControlPoints(wxDC& dc)
257 {
258 if (m_previousHandler)
259 m_previousHandler->OnDrawControlPoints(dc);
260 }
261
262 void wxShapeEvtHandler::OnEraseControlPoints(wxDC& dc)
263 {
264 if (m_previousHandler)
265 m_previousHandler->OnEraseControlPoints(dc);
266 }
267
268 // Can override this to prevent or intercept line reordering.
269 void wxShapeEvtHandler::OnChangeAttachment(int attachment, wxLineShape* line, wxList& ordering)
270 {
271 if (m_previousHandler)
272 m_previousHandler->OnChangeAttachment(attachment, line, ordering);
273 }
274
275 IMPLEMENT_ABSTRACT_CLASS(wxShape, wxShapeEvtHandler)
276
277 wxShape::wxShape(wxShapeCanvas *can)
278 {
279 m_eventHandler = this;
280 SetShape(this);
281 m_id = 0;
282 m_formatted = FALSE;
283 m_canvas = can;
284 m_xpos = 0.0; m_ypos = 0.0;
285 m_pen = g_oglBlackPen;
286 m_brush = wxWHITE_BRUSH;
287 m_font = g_oglNormalFont;
288 m_textColour = wxBLACK;
289 m_textColourName = "BLACK";
290 m_visible = FALSE;
291 m_clientData = NULL;
292 m_selected = FALSE;
293 m_attachmentMode = ATTACHMENT_MODE_NONE;
294 m_spaceAttachments = TRUE;
295 m_disableLabel = FALSE;
296 m_fixedWidth = FALSE;
297 m_fixedHeight = FALSE;
298 m_drawHandles = TRUE;
299 m_sensitivity = OP_ALL;
300 m_draggable = TRUE;
301 m_parent = NULL;
302 m_formatMode = FORMAT_CENTRE_HORIZ | FORMAT_CENTRE_VERT;
303 m_shadowMode = SHADOW_NONE;
304 m_shadowOffsetX = 6;
305 m_shadowOffsetY = 6;
306 m_shadowBrush = wxBLACK_BRUSH;
307 m_textMarginX = 5;
308 m_textMarginY = 5;
309 m_regionName = "0";
310 m_centreResize = TRUE;
311 m_maintainAspectRatio = FALSE;
312 m_highlighted = FALSE;
313 m_rotation = 0.0;
314 m_branchNeckLength = 10;
315 m_branchStemLength = 10;
316 m_branchSpacing = 10;
317 m_branchStyle = BRANCHING_ATTACHMENT_NORMAL;
318
319 // Set up a default region. Much of the above will be put into
320 // the region eventually (the duplication is for compatibility)
321 wxShapeRegion *region = new wxShapeRegion;
322 m_regions.Append(region);
323 region->SetName("0");
324 region->SetFont(g_oglNormalFont);
325 region->SetFormatMode(FORMAT_CENTRE_HORIZ | FORMAT_CENTRE_VERT);
326 region->SetColour("BLACK");
327 }
328
329 wxShape::~wxShape()
330 {
331 if (m_parent)
332 m_parent->GetChildren().DeleteObject(this);
333
334 ClearText();
335 ClearRegions();
336 ClearAttachments();
337
338 if (m_canvas)
339 m_canvas->RemoveShape(this);
340
341 GetEventHandler()->OnDelete();
342 }
343
344 void wxShape::SetHighlight(bool hi, bool recurse)
345 {
346 m_highlighted = hi;
347 if (recurse)
348 {
349 wxNode *node = m_children.First();
350 while (node)
351 {
352 wxShape *child = (wxShape *)node->Data();
353 child->SetHighlight(hi, recurse);
354 node = node->Next();
355 }
356 }
357 }
358
359 void wxShape::SetSensitivityFilter(int sens, bool recursive)
360 {
361 if (sens & OP_DRAG_LEFT)
362 m_draggable = TRUE;
363 else
364 m_draggable = FALSE;
365
366 m_sensitivity = sens;
367 if (recursive)
368 {
369 wxNode *node = m_children.First();
370 while (node)
371 {
372 wxShape *obj = (wxShape *)node->Data();
373 obj->SetSensitivityFilter(sens, TRUE);
374 node = node->Next();
375 }
376 }
377 }
378
379 void wxShape::SetDraggable(bool drag, bool recursive)
380 {
381 m_draggable = drag;
382 if (m_draggable)
383 m_sensitivity |= OP_DRAG_LEFT;
384 else
385 if (m_sensitivity & OP_DRAG_LEFT)
386 m_sensitivity = m_sensitivity - OP_DRAG_LEFT;
387
388 if (recursive)
389 {
390 wxNode *node = m_children.First();
391 while (node)
392 {
393 wxShape *obj = (wxShape *)node->Data();
394 obj->SetDraggable(drag, TRUE);
395 node = node->Next();
396 }
397 }
398 }
399
400 void wxShape::SetDrawHandles(bool drawH)
401 {
402 m_drawHandles = drawH;
403 wxNode *node = m_children.First();
404 while (node)
405 {
406 wxShape *obj = (wxShape *)node->Data();
407 obj->SetDrawHandles(drawH);
408 node = node->Next();
409 }
410 }
411
412 void wxShape::SetShadowMode(int mode, bool redraw)
413 {
414 if (redraw && GetCanvas())
415 {
416 wxClientDC dc(GetCanvas());
417 GetCanvas()->PrepareDC(dc);
418 Erase(dc);
419
420 m_shadowMode = mode;
421
422 Draw(dc);
423 }
424 else
425 {
426 m_shadowMode = mode;
427 }
428 }
429
430 void wxShape::SetCanvas(wxShapeCanvas *theCanvas)
431 {
432 m_canvas = theCanvas;
433 wxNode *node = m_children.First();
434 while (node)
435 {
436 wxShape *child = (wxShape *)node->Data();
437 child->SetCanvas(theCanvas);
438 node = node->Next();
439 }
440 }
441
442 void wxShape::AddToCanvas(wxShapeCanvas *theCanvas, wxShape *addAfter)
443 {
444 theCanvas->AddShape(this, addAfter);
445 wxNode *node = m_children.First();
446 wxShape *lastImage = this;
447 while (node)
448 {
449 wxShape *object = (wxShape *)node->Data();
450 object->AddToCanvas(theCanvas, lastImage);
451 lastImage = object;
452
453 node = node->Next();
454 }
455 }
456
457 // Insert at front of canvas
458 void wxShape::InsertInCanvas(wxShapeCanvas *theCanvas)
459 {
460 theCanvas->InsertShape(this);
461 wxNode *node = m_children.First();
462 wxShape *lastImage = this;
463 while (node)
464 {
465 wxShape *object = (wxShape *)node->Data();
466 object->AddToCanvas(theCanvas, lastImage);
467 lastImage = object;
468
469 node = node->Next();
470 }
471 }
472
473 void wxShape::RemoveFromCanvas(wxShapeCanvas *theCanvas)
474 {
475 if (Selected())
476 Select(FALSE);
477 theCanvas->RemoveShape(this);
478 wxNode *node = m_children.First();
479 while (node)
480 {
481 wxShape *object = (wxShape *)node->Data();
482 object->RemoveFromCanvas(theCanvas);
483
484 node = node->Next();
485 }
486 }
487
488 void wxShape::ClearAttachments()
489 {
490 wxNode *node = m_attachmentPoints.First();
491 while (node)
492 {
493 wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
494 delete point;
495 node = node->Next();
496 }
497 m_attachmentPoints.Clear();
498 }
499
500 void wxShape::ClearText(int regionId)
501 {
502 if (regionId == 0)
503 {
504 m_text.DeleteContents(TRUE);
505 m_text.Clear();
506 m_text.DeleteContents(FALSE);
507 }
508 wxNode *node = m_regions.Nth(regionId);
509 if (!node)
510 return;
511 wxShapeRegion *region = (wxShapeRegion *)node->Data();
512 region->ClearText();
513 }
514
515 void wxShape::ClearRegions()
516 {
517 wxNode *node = m_regions.First();
518 while (node)
519 {
520 wxShapeRegion *region = (wxShapeRegion *)node->Data();
521 wxNode *next = node->Next();
522 delete region;
523 delete node;
524 node = next;
525 }
526 }
527
528 void wxShape::AddRegion(wxShapeRegion *region)
529 {
530 m_regions.Append(region);
531 }
532
533 void wxShape::SetDefaultRegionSize()
534 {
535 wxNode *node = m_regions.First();
536 if (!node) return;
537 wxShapeRegion *region = (wxShapeRegion *)node->Data();
538 double w, h;
539 GetBoundingBoxMin(&w, &h);
540 region->SetSize(w, h);
541 }
542
543 bool wxShape::HitTest(double x, double y, int *attachment, double *distance)
544 {
545 // if (!sensitive)
546 // return FALSE;
547
548 double width = 0.0, height = 0.0;
549 GetBoundingBoxMin(&width, &height);
550 if (fabs(width) < 4.0) width = 4.0;
551 if (fabs(height) < 4.0) height = 4.0;
552
553 width += (double)4.0; height += (double)4.0; // Allowance for inaccurate mousing
554
555 double left = (double)(m_xpos - (width/2.0));
556 double top = (double)(m_ypos - (height/2.0));
557 double right = (double)(m_xpos + (width/2.0));
558 double bottom = (double)(m_ypos + (height/2.0));
559
560 int nearest_attachment = 0;
561
562 // If within the bounding box, check the attachment points
563 // within the object.
564
565 if (x >= left && x <= right && y >= top && y <= bottom)
566 {
567 int n = GetNumberOfAttachments();
568 double nearest = 999999.0;
569
570 // GetAttachmentPosition[Edge] takes a logical attachment position,
571 // i.e. if it's rotated through 90%, position 0 is East-facing.
572
573 for (int i = 0; i < n; i++)
574 {
575 double xp, yp;
576 if (GetAttachmentPositionEdge(i, &xp, &yp))
577 {
578 double l = (double)sqrt(((xp - x) * (xp - x)) +
579 ((yp - y) * (yp - y)));
580
581 if (l < nearest)
582 {
583 nearest = l;
584 nearest_attachment = i;
585 }
586 }
587 }
588 *attachment = nearest_attachment;
589 *distance = nearest;
590 return TRUE;
591 }
592 else return FALSE;
593 }
594
595 // Format a text string according to the region size, adding
596 // strings with positions to region text list
597
598 static bool GraphicsInSizeToContents = FALSE; // Infinite recursion elimination
599 void wxShape::FormatText(wxDC& dc, const wxString& s, int i)
600 {
601 double w, h;
602 ClearText(i);
603
604 if (m_regions.Number() < 1)
605 return;
606 wxNode *node = m_regions.Nth(i);
607 if (!node)
608 return;
609
610 wxShapeRegion *region = (wxShapeRegion *)node->Data();
611 region->SetText(s);
612 dc.SetFont(* region->GetFont());
613
614 region->GetSize(&w, &h);
615
616 wxStringList *stringList = oglFormatText(dc, s, (w-5), (h-5), region->GetFormatMode());
617 node = stringList->First();
618 while (node)
619 {
620 char *s = (char *)node->Data();
621 wxShapeTextLine *line = new wxShapeTextLine(0.0, 0.0, s);
622 region->GetFormattedText().Append((wxObject *)line);
623 node = node->Next();
624 }
625 delete stringList;
626 double actualW = w;
627 double actualH = h;
628 // Don't try to resize an object with more than one image (this case should be dealt
629 // with by overriden handlers)
630 if ((region->GetFormatMode() & FORMAT_SIZE_TO_CONTENTS) &&
631 (region->GetFormattedText().Number() > 0) &&
632 (m_regions.Number() == 1) && !GraphicsInSizeToContents)
633 {
634 oglGetCentredTextExtent(dc, &(region->GetFormattedText()), m_xpos, m_ypos, w, h, &actualW, &actualH);
635 if ((actualW+m_textMarginX != w ) || (actualH+m_textMarginY != h))
636 {
637 // If we are a descendant of a composite, must make sure the composite gets
638 // resized properly
639 wxShape *topAncestor = GetTopAncestor();
640
641 if (topAncestor != this)
642 {
643 // Make sure we don't recurse infinitely
644 GraphicsInSizeToContents = TRUE;
645
646 wxCompositeShape *composite = (wxCompositeShape *)topAncestor;
647 composite->Erase(dc);
648 SetSize(actualW+m_textMarginX, actualH+m_textMarginY);
649 Move(dc, m_xpos, m_ypos);
650 composite->CalculateSize();
651 if (composite->Selected())
652 {
653 composite->DeleteControlPoints(& dc);
654 composite->MakeControlPoints();
655 composite->MakeMandatoryControlPoints();
656 }
657 // Where infinite recursion might happen if we didn't stop it
658 composite->Draw(dc);
659
660 GraphicsInSizeToContents = FALSE;
661 }
662 else
663 {
664 Erase(dc);
665 SetSize(actualW+m_textMarginX, actualH+m_textMarginY);
666 Move(dc, m_xpos, m_ypos);
667 }
668 SetSize(actualW+m_textMarginX, actualH+m_textMarginY);
669 Move(dc, m_xpos, m_ypos);
670 EraseContents(dc);
671 }
672 }
673 oglCentreText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, actualW, actualH, region->GetFormatMode());
674 m_formatted = TRUE;
675 }
676
677 void wxShape::Recentre(wxDC& dc)
678 {
679 double w, h;
680 GetBoundingBoxMin(&w, &h);
681
682 int noRegions = m_regions.Number();
683 for (int i = 0; i < noRegions; i++)
684 {
685 wxNode *node = m_regions.Nth(i);
686 if (node)
687 {
688 wxShapeRegion *region = (wxShapeRegion *)node->Data();
689 oglCentreText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, w, h, region->GetFormatMode());
690 }
691 }
692 }
693
694 bool wxShape::GetPerimeterPoint(double x1, double y1,
695 double x2, double y2,
696 double *x3, double *y3)
697 {
698 return FALSE;
699 }
700
701 void wxShape::SetPen(wxPen *the_pen)
702 {
703 m_pen = the_pen;
704 }
705
706 void wxShape::SetBrush(wxBrush *the_brush)
707 {
708 m_brush = the_brush;
709 }
710
711 // Get the top-most (non-division) ancestor, or self
712 wxShape *wxShape::GetTopAncestor()
713 {
714 if (!GetParent())
715 return this;
716
717 if (GetParent()->IsKindOf(CLASSINFO(wxDivisionShape)))
718 return this;
719 else return GetParent()->GetTopAncestor();
720 }
721
722 /*
723 * Region functions
724 *
725 */
726 void wxShape::SetFont(wxFont *the_font, int regionId)
727 {
728 m_font = the_font;
729 wxNode *node = m_regions.Nth(regionId);
730 if (!node)
731 return;
732 wxShapeRegion *region = (wxShapeRegion *)node->Data();
733 region->SetFont(the_font);
734 }
735
736 wxFont *wxShape::GetFont(int n) const
737 {
738 wxNode *node = m_regions.Nth(n);
739 if (!node)
740 return NULL;
741 wxShapeRegion *region = (wxShapeRegion *)node->Data();
742 return region->GetFont();
743 }
744
745 void wxShape::SetFormatMode(int mode, int regionId)
746 {
747 wxNode *node = m_regions.Nth(regionId);
748 if (!node)
749 return;
750 wxShapeRegion *region = (wxShapeRegion *)node->Data();
751 region->SetFormatMode(mode);
752 }
753
754 int wxShape::GetFormatMode(int regionId) const
755 {
756 wxNode *node = m_regions.Nth(regionId);
757 if (!node)
758 return 0;
759 wxShapeRegion *region = (wxShapeRegion *)node->Data();
760 return region->GetFormatMode();
761 }
762
763 void wxShape::SetTextColour(const wxString& the_colour, int regionId)
764 {
765 wxColour *wxcolour = wxTheColourDatabase->FindColour(the_colour);
766 m_textColour = wxcolour;
767 m_textColourName = the_colour;
768
769 wxNode *node = m_regions.Nth(regionId);
770 if (!node)
771 return;
772 wxShapeRegion *region = (wxShapeRegion *)node->Data();
773 region->SetColour(the_colour);
774 }
775
776 wxString wxShape::GetTextColour(int regionId) const
777 {
778 wxNode *node = m_regions.Nth(regionId);
779 if (!node)
780 return wxString("");
781 wxShapeRegion *region = (wxShapeRegion *)node->Data();
782 return region->GetColour();
783 }
784
785 void wxShape::SetRegionName(const wxString& name, int regionId)
786 {
787 wxNode *node = m_regions.Nth(regionId);
788 if (!node)
789 return;
790 wxShapeRegion *region = (wxShapeRegion *)node->Data();
791 region->SetName(name);
792 }
793
794 wxString wxShape::GetRegionName(int regionId)
795 {
796 wxNode *node = m_regions.Nth(regionId);
797 if (!node)
798 return wxString("");
799 wxShapeRegion *region = (wxShapeRegion *)node->Data();
800 return region->GetName();
801 }
802
803 int wxShape::GetRegionId(const wxString& name)
804 {
805 wxNode *node = m_regions.First();
806 int i = 0;
807 while (node)
808 {
809 wxShapeRegion *region = (wxShapeRegion *)node->Data();
810 if (region->GetName() == name)
811 return i;
812 node = node->Next();
813 i ++;
814 }
815 return -1;
816 }
817
818 // Name all m_regions in all subimages recursively.
819 void wxShape::NameRegions(const wxString& parentName)
820 {
821 int n = GetNumberOfTextRegions();
822 char buf[100];
823 for (int i = 0; i < n; i++)
824 {
825 if (parentName.Length() > 0)
826 sprintf(buf, "%s.%d", (const char*) parentName, i);
827 else
828 sprintf(buf, "%d", i);
829 SetRegionName(buf, i);
830 }
831 wxNode *node = m_children.First();
832 int j = 0;
833 while (node)
834 {
835 wxShape *child = (wxShape *)node->Data();
836 if (parentName.Length() > 0)
837 sprintf(buf, "%s.%d", (const char*) parentName, j);
838 else
839 sprintf(buf, "%d", j);
840 child->NameRegions(buf);
841 node = node->Next();
842 j ++;
843 }
844 }
845
846 // Get a region by name, possibly looking recursively into composites.
847 wxShape *wxShape::FindRegion(const wxString& name, int *regionId)
848 {
849 int id = GetRegionId(name);
850 if (id > -1)
851 {
852 *regionId = id;
853 return this;
854 }
855
856 wxNode *node = m_children.First();
857 while (node)
858 {
859 wxShape *child = (wxShape *)node->Data();
860 wxShape *actualImage = child->FindRegion(name, regionId);
861 if (actualImage)
862 return actualImage;
863 node = node->Next();
864 }
865 return NULL;
866 }
867
868 // Finds all region names for this image (composite or simple).
869 // Supply empty string list.
870 void wxShape::FindRegionNames(wxStringList& list)
871 {
872 int n = GetNumberOfTextRegions();
873 for (int i = 0; i < n; i++)
874 {
875 wxString name(GetRegionName(i));
876 list.Add((const char*) name);
877 }
878
879 wxNode *node = m_children.First();
880 while (node)
881 {
882 wxShape *child = (wxShape *)node->Data();
883 child->FindRegionNames(list);
884 node = node->Next();
885 }
886 }
887
888 void wxShape::AssignNewIds()
889 {
890 // if (m_id == 0)
891 m_id = wxNewId();
892 wxNode *node = m_children.First();
893 while (node)
894 {
895 wxShape *child = (wxShape *)node->Data();
896 child->AssignNewIds();
897 node = node->Next();
898 }
899 }
900
901 void wxShape::OnDraw(wxDC& dc)
902 {
903 }
904
905 void wxShape::OnMoveLinks(wxDC& dc)
906 {
907 // Want to set the ends of all attached links
908 // to point to/from this object
909
910 wxNode *current = m_lines.First();
911 while (current)
912 {
913 wxLineShape *line = (wxLineShape *)current->Data();
914 line->GetEventHandler()->OnMoveLink(dc);
915 current = current->Next();
916 }
917 }
918
919
920 void wxShape::OnDrawContents(wxDC& dc)
921 {
922 double bound_x, bound_y;
923 GetBoundingBoxMin(&bound_x, &bound_y);
924 if (m_regions.Number() < 1) return;
925
926 if (m_pen) dc.SetPen(* m_pen);
927
928 wxShapeRegion *region = (wxShapeRegion *)m_regions.First()->Data();
929 if (region->GetFont()) dc.SetFont(* region->GetFont());
930
931 dc.SetTextForeground(* (region->GetActualColourObject()));
932 dc.SetBackgroundMode(wxTRANSPARENT);
933 if (!m_formatted)
934 {
935 oglCentreText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, bound_x, bound_y, region->GetFormatMode());
936 m_formatted = TRUE;
937 }
938 if (!GetDisableLabel())
939 {
940 oglDrawFormattedText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, bound_x, bound_y, region->GetFormatMode());
941 }
942 }
943
944 void wxShape::DrawContents(wxDC& dc)
945 {
946 GetEventHandler()->OnDrawContents(dc);
947 }
948
949 void wxShape::OnSize(double x, double y)
950 {
951 }
952
953 bool wxShape::OnMovePre(wxDC& dc, double x, double y, double old_x, double old_y, bool display)
954 {
955 return TRUE;
956 }
957
958 void wxShape::OnMovePost(wxDC& dc, double x, double y, double old_x, double old_y, bool display)
959 {
960 }
961
962 void wxShape::OnErase(wxDC& dc)
963 {
964 if (!m_visible)
965 return;
966
967 // Erase links
968 wxNode *current = m_lines.First();
969 while (current)
970 {
971 wxLineShape *line = (wxLineShape *)current->Data();
972 line->GetEventHandler()->OnErase(dc);
973 current = current->Next();
974 }
975 GetEventHandler()->OnEraseContents(dc);
976 }
977
978 void wxShape::OnEraseContents(wxDC& dc)
979 {
980 if (!m_visible)
981 return;
982
983 double maxX, maxY, minX, minY;
984 double xp = GetX();
985 double yp = GetY();
986 GetBoundingBoxMin(&minX, &minY);
987 GetBoundingBoxMax(&maxX, &maxY);
988 double topLeftX = (double)(xp - (maxX / 2.0) - 2.0);
989 double topLeftY = (double)(yp - (maxY / 2.0) - 2.0);
990
991 int penWidth = 0;
992 if (m_pen)
993 penWidth = m_pen->GetWidth();
994
995 dc.SetPen(* g_oglWhiteBackgroundPen);
996 dc.SetBrush(* g_oglWhiteBackgroundBrush);
997 dc.DrawRectangle(WXROUND(topLeftX - penWidth), WXROUND(topLeftY - penWidth),
998 WXROUND(maxX + penWidth*2.0 + 4.0), WXROUND(maxY + penWidth*2.0 + 4.0));
999 }
1000
1001 void wxShape::EraseLinks(wxDC& dc, int attachment, bool recurse)
1002 {
1003 if (!m_visible)
1004 return;
1005
1006 wxNode *current = m_lines.First();
1007 while (current)
1008 {
1009 wxLineShape *line = (wxLineShape *)current->Data();
1010 if (attachment == -1 || ((line->GetTo() == this && line->GetAttachmentTo() == attachment) ||
1011 (line->GetFrom() == this && line->GetAttachmentFrom() == attachment)))
1012 line->GetEventHandler()->OnErase(dc);
1013 current = current->Next();
1014 }
1015 if (recurse)
1016 {
1017 wxNode *node = m_children.First();
1018 while (node)
1019 {
1020 wxShape *child = (wxShape *)node->Data();
1021 child->EraseLinks(dc, attachment, recurse);
1022 node = node->Next();
1023 }
1024 }
1025 }
1026
1027 void wxShape::DrawLinks(wxDC& dc, int attachment, bool recurse)
1028 {
1029 if (!m_visible)
1030 return;
1031
1032 wxNode *current = m_lines.First();
1033 while (current)
1034 {
1035 wxLineShape *line = (wxLineShape *)current->Data();
1036 if (attachment == -1 ||
1037 (line->GetTo() == this && line->GetAttachmentTo() == attachment) ||
1038 (line->GetFrom() == this && line->GetAttachmentFrom() == attachment))
1039 line->Draw(dc);
1040 current = current->Next();
1041 }
1042 if (recurse)
1043 {
1044 wxNode *node = m_children.First();
1045 while (node)
1046 {
1047 wxShape *child = (wxShape *)node->Data();
1048 child->DrawLinks(dc, attachment, recurse);
1049 node = node->Next();
1050 }
1051 }
1052 }
1053
1054 // Returns TRUE if pt1 <= pt2 in the sense that one point comes before another on an
1055 // edge of the shape.
1056 // attachmentPoint is the attachment point (= side) in question.
1057
1058 // This is the default, rectangular implementation.
1059 bool wxShape::AttachmentSortTest(int attachmentPoint, const wxRealPoint& pt1, const wxRealPoint& pt2)
1060 {
1061 int physicalAttachment = LogicalToPhysicalAttachment(attachmentPoint);
1062 switch (physicalAttachment)
1063 {
1064 case 0:
1065 case 2:
1066 {
1067 return (pt1.x <= pt2.x) ;
1068 break;
1069 }
1070 case 1:
1071 case 3:
1072 {
1073 return (pt1.y <= pt2.y) ;
1074 break;
1075 }
1076 }
1077
1078 return FALSE;
1079 }
1080
1081 bool wxShape::MoveLineToNewAttachment(wxDC& dc, wxLineShape *to_move,
1082 double x, double y)
1083 {
1084 if (GetAttachmentMode() == ATTACHMENT_MODE_NONE)
1085 return FALSE;
1086
1087 int newAttachment, oldAttachment;
1088 double distance;
1089
1090 // Is (x, y) on this object? If so, find the new attachment point
1091 // the user has moved the point to
1092 bool hit = HitTest(x, y, &newAttachment, &distance);
1093 if (!hit)
1094 return FALSE;
1095
1096 EraseLinks(dc);
1097
1098 if (to_move->GetTo() == this)
1099 oldAttachment = to_move->GetAttachmentTo();
1100 else
1101 oldAttachment = to_move->GetAttachmentFrom();
1102
1103 // The links in a new ordering.
1104 wxList newOrdering;
1105
1106 // First, add all links to the new list.
1107 wxNode *node = m_lines.First();
1108 while (node)
1109 {
1110 newOrdering.Append(node->Data());
1111 node = node->Next();
1112 }
1113
1114 // Delete the line object from the list of links; we're going to move
1115 // it to another position in the list
1116 newOrdering.DeleteObject(to_move);
1117
1118 double old_x = (double) -99999.9;
1119 double old_y = (double) -99999.9;
1120
1121 node = newOrdering.First();
1122 bool found = FALSE;
1123
1124 while (!found && node)
1125 {
1126 wxLineShape *line = (wxLineShape *)node->Data();
1127 if ((line->GetTo() == this && oldAttachment == line->GetAttachmentTo()) ||
1128 (line->GetFrom() == this && oldAttachment == line->GetAttachmentFrom()))
1129 {
1130 double startX, startY, endX, endY;
1131 double xp, yp;
1132 line->GetEnds(&startX, &startY, &endX, &endY);
1133 if (line->GetTo() == this)
1134 {
1135 xp = endX;
1136 yp = endY;
1137 } else
1138 {
1139 xp = startX;
1140 yp = startY;
1141 }
1142
1143 wxRealPoint thisPoint(xp, yp);
1144 wxRealPoint lastPoint(old_x, old_y);
1145 wxRealPoint newPoint(x, y);
1146
1147 if (AttachmentSortTest(newAttachment, newPoint, thisPoint) && AttachmentSortTest(newAttachment, lastPoint, newPoint))
1148 {
1149 found = TRUE;
1150 newOrdering.Insert(node, to_move);
1151 }
1152
1153 old_x = xp;
1154 old_y = yp;
1155 }
1156 node = node->Next();
1157 }
1158
1159 if (!found)
1160 newOrdering.Append(to_move);
1161
1162 GetEventHandler()->OnChangeAttachment(newAttachment, to_move, newOrdering);
1163
1164 return TRUE;
1165 }
1166
1167 void wxShape::OnChangeAttachment(int attachment, wxLineShape* line, wxList& ordering)
1168 {
1169 if (line->GetTo() == this)
1170 line->SetAttachmentTo(attachment);
1171 else
1172 line->SetAttachmentFrom(attachment);
1173
1174 ApplyAttachmentOrdering(ordering);
1175
1176 wxClientDC dc(GetCanvas());
1177 GetCanvas()->PrepareDC(dc);
1178
1179 MoveLinks(dc);
1180
1181 if (!GetCanvas()->GetQuickEditMode()) GetCanvas()->Redraw(dc);
1182 }
1183
1184 // Reorders the lines according to the given list.
1185 void wxShape::ApplyAttachmentOrdering(wxList& linesToSort)
1186 {
1187 // This is a temporary store of all the lines.
1188 wxList linesStore;
1189
1190 wxNode *node = m_lines.First();
1191 while (node)
1192 {
1193 wxLineShape *line = (wxLineShape *)node->Data();
1194 linesStore.Append(line);
1195 node = node->Next();;
1196 }
1197
1198 m_lines.Clear();
1199
1200 node = linesToSort.First();
1201 while (node)
1202 {
1203 wxLineShape *line = (wxLineShape *)node->Data();
1204 if (linesStore.Member(line))
1205 {
1206 // Done this one
1207 linesStore.DeleteObject(line);
1208 m_lines.Append(line);
1209 }
1210 node = node->Next();
1211 }
1212
1213 // Now add any lines that haven't been listed in linesToSort.
1214 node = linesStore.First();
1215 while (node)
1216 {
1217 wxLineShape *line = (wxLineShape *)node->Data();
1218 m_lines.Append(line);
1219 node = node->Next();
1220 }
1221 }
1222
1223 // Reorders the lines coming into the node image at this attachment
1224 // position, in the order in which they appear in linesToSort.
1225 // Any remaining lines not in the list will be added to the end.
1226 void wxShape::SortLines(int attachment, wxList& linesToSort)
1227 {
1228 // This is a temporary store of all the lines at this attachment
1229 // point. We'll tick them off as we've processed them.
1230 wxList linesAtThisAttachment;
1231
1232 wxNode *node = m_lines.First();
1233 while (node)
1234 {
1235 wxLineShape *line = (wxLineShape *)node->Data();
1236 wxNode *next = node->Next();
1237 if ((line->GetTo() == this && line->GetAttachmentTo() == attachment) ||
1238 (line->GetFrom() == this && line->GetAttachmentFrom() == attachment))
1239 {
1240 linesAtThisAttachment.Append(line);
1241 delete node;
1242 node = next;
1243 }
1244 else node = node->Next();
1245 }
1246
1247 node = linesToSort.First();
1248 while (node)
1249 {
1250 wxLineShape *line = (wxLineShape *)node->Data();
1251 if (linesAtThisAttachment.Member(line))
1252 {
1253 // Done this one
1254 linesAtThisAttachment.DeleteObject(line);
1255 m_lines.Append(line);
1256 }
1257 node = node->Next();
1258 }
1259
1260 // Now add any lines that haven't been listed in linesToSort.
1261 node = linesAtThisAttachment.First();
1262 while (node)
1263 {
1264 wxLineShape *line = (wxLineShape *)node->Data();
1265 m_lines.Append(line);
1266 node = node->Next();
1267 }
1268 }
1269
1270 void wxShape::OnHighlight(wxDC& dc)
1271 {
1272 }
1273
1274 void wxShape::OnLeftClick(double x, double y, int keys, int attachment)
1275 {
1276 if ((m_sensitivity & OP_CLICK_LEFT) != OP_CLICK_LEFT)
1277 {
1278 attachment = 0;
1279 double dist;
1280 if (m_parent)
1281 {
1282 m_parent->HitTest(x, y, &attachment, &dist);
1283 m_parent->GetEventHandler()->OnLeftClick(x, y, keys, attachment);
1284 }
1285 return;
1286 }
1287 }
1288
1289 void wxShape::OnRightClick(double x, double y, int keys, int attachment)
1290 {
1291 if ((m_sensitivity & OP_CLICK_RIGHT) != OP_CLICK_RIGHT)
1292 {
1293 attachment = 0;
1294 double dist;
1295 if (m_parent)
1296 {
1297 m_parent->HitTest(x, y, &attachment, &dist);
1298 m_parent->GetEventHandler()->OnRightClick(x, y, keys, attachment);
1299 }
1300 return;
1301 }
1302 }
1303
1304 double DragOffsetX = 0.0;
1305 double DragOffsetY = 0.0;
1306
1307 void wxShape::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
1308 {
1309 if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT)
1310 {
1311 attachment = 0;
1312 double dist;
1313 if (m_parent)
1314 {
1315 m_parent->HitTest(x, y, &attachment, &dist);
1316 m_parent->GetEventHandler()->OnDragLeft(draw, x, y, keys, attachment);
1317 }
1318 return;
1319 }
1320
1321 wxClientDC dc(GetCanvas());
1322 GetCanvas()->PrepareDC(dc);
1323
1324 dc.SetLogicalFunction(OGLRBLF);
1325
1326 wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
1327 dc.SetPen(dottedPen);
1328 dc.SetBrush(* wxTRANSPARENT_BRUSH);
1329
1330 double xx, yy;
1331 xx = x + DragOffsetX;
1332 yy = y + DragOffsetY;
1333
1334 m_canvas->Snap(&xx, &yy);
1335 // m_xpos = xx; m_ypos = yy;
1336 double w, h;
1337 GetBoundingBoxMax(&w, &h);
1338 GetEventHandler()->OnDrawOutline(dc, xx, yy, w, h);
1339 }
1340
1341 void wxShape::OnBeginDragLeft(double x, double y, int keys, int attachment)
1342 {
1343 if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT)
1344 {
1345 attachment = 0;
1346 double dist;
1347 if (m_parent)
1348 {
1349 m_parent->HitTest(x, y, &attachment, &dist);
1350 m_parent->GetEventHandler()->OnBeginDragLeft(x, y, keys, attachment);
1351 }
1352 return;
1353 }
1354
1355 DragOffsetX = m_xpos - x;
1356 DragOffsetY = m_ypos - y;
1357
1358 wxClientDC dc(GetCanvas());
1359 GetCanvas()->PrepareDC(dc);
1360
1361 // New policy: don't erase shape until end of drag.
1362 // Erase(dc);
1363
1364 double xx, yy;
1365 xx = x + DragOffsetX;
1366 yy = y + DragOffsetY;
1367 m_canvas->Snap(&xx, &yy);
1368 // m_xpos = xx; m_ypos = yy;
1369 dc.SetLogicalFunction(OGLRBLF);
1370
1371 wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
1372 dc.SetPen(dottedPen);
1373 dc.SetBrush((* wxTRANSPARENT_BRUSH));
1374
1375 double w, h;
1376 GetBoundingBoxMax(&w, &h);
1377 GetEventHandler()->OnDrawOutline(dc, xx, yy, w, h);
1378 m_canvas->CaptureMouse();
1379 }
1380
1381 void wxShape::OnEndDragLeft(double x, double y, int keys, int attachment)
1382 {
1383 m_canvas->ReleaseMouse();
1384 if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT)
1385 {
1386 attachment = 0;
1387 double dist;
1388 if (m_parent)
1389 {
1390 m_parent->HitTest(x, y, &attachment, &dist);
1391 m_parent->GetEventHandler()->OnEndDragLeft(x, y, keys, attachment);
1392 }
1393 return;
1394 }
1395
1396 wxClientDC dc(GetCanvas());
1397 GetCanvas()->PrepareDC(dc);
1398
1399 dc.SetLogicalFunction(wxCOPY);
1400
1401 double xx = x + DragOffsetX;
1402 double yy = y + DragOffsetY;
1403 m_canvas->Snap(&xx, &yy);
1404 // canvas->Snap(&m_xpos, &m_ypos);
1405
1406 // New policy: erase shape at end of drag.
1407 Erase(dc);
1408
1409 Move(dc, xx, yy);
1410 if (m_canvas && !m_canvas->GetQuickEditMode()) m_canvas->Redraw(dc);
1411 }
1412
1413 void wxShape::OnDragRight(bool draw, double x, double y, int keys, int attachment)
1414 {
1415 if ((m_sensitivity & OP_DRAG_RIGHT) != OP_DRAG_RIGHT)
1416 {
1417 attachment = 0;
1418 double dist;
1419 if (m_parent)
1420 {
1421 m_parent->HitTest(x, y, &attachment, &dist);
1422 m_parent->GetEventHandler()->OnDragRight(draw, x, y, keys, attachment);
1423 }
1424 return;
1425 }
1426 }
1427
1428 void wxShape::OnBeginDragRight(double x, double y, int keys, int attachment)
1429 {
1430 if ((m_sensitivity & OP_DRAG_RIGHT) != OP_DRAG_RIGHT)
1431 {
1432 attachment = 0;
1433 double dist;
1434 if (m_parent)
1435 {
1436 m_parent->HitTest(x, y, &attachment, &dist);
1437 m_parent->GetEventHandler()->OnBeginDragRight(x, y, keys, attachment);
1438 }
1439 return;
1440 }
1441 }
1442
1443 void wxShape::OnEndDragRight(double x, double y, int keys, int attachment)
1444 {
1445 if ((m_sensitivity & OP_DRAG_RIGHT) != OP_DRAG_RIGHT)
1446 {
1447 attachment = 0;
1448 double dist;
1449 if (m_parent)
1450 {
1451 m_parent->HitTest(x, y, &attachment, &dist);
1452 m_parent->GetEventHandler()->OnEndDragRight(x, y, keys, attachment);
1453 }
1454 return;
1455 }
1456 }
1457
1458 void wxShape::OnDrawOutline(wxDC& dc, double x, double y, double w, double h)
1459 {
1460 double top_left_x = (double)(x - w/2.0);
1461 double top_left_y = (double)(y - h/2.0);
1462 double top_right_x = (double)(top_left_x + w);
1463 double top_right_y = (double)top_left_y;
1464 double bottom_left_x = (double)top_left_x;
1465 double bottom_left_y = (double)(top_left_y + h);
1466 double bottom_right_x = (double)top_right_x;
1467 double bottom_right_y = (double)bottom_left_y;
1468
1469 wxPoint points[5];
1470 points[0].x = WXROUND(top_left_x); points[0].y = WXROUND(top_left_y);
1471 points[1].x = WXROUND(top_right_x); points[1].y = WXROUND(top_right_y);
1472 points[2].x = WXROUND(bottom_right_x); points[2].y = WXROUND(bottom_right_y);
1473 points[3].x = WXROUND(bottom_left_x); points[3].y = WXROUND(bottom_left_y);
1474 points[4].x = WXROUND(top_left_x); points[4].y = WXROUND(top_left_y);
1475
1476 dc.DrawLines(5, points);
1477 }
1478
1479 void wxShape::Attach(wxShapeCanvas *can)
1480 {
1481 m_canvas = can;
1482 }
1483
1484 void wxShape::Detach()
1485 {
1486 m_canvas = NULL;
1487 }
1488
1489 void wxShape::Move(wxDC& dc, double x, double y, bool display)
1490 {
1491 double old_x = m_xpos;
1492 double old_y = m_ypos;
1493
1494 if (!GetEventHandler()->OnMovePre(dc, x, y, old_x, old_y, display))
1495 {
1496 // m_xpos = old_x;
1497 // m_ypos = old_y;
1498 return;
1499 }
1500
1501 m_xpos = x; m_ypos = y;
1502
1503 ResetControlPoints();
1504
1505 if (display)
1506 Draw(dc);
1507
1508 MoveLinks(dc);
1509
1510 GetEventHandler()->OnMovePost(dc, x, y, old_x, old_y, display);
1511 }
1512
1513 void wxShape::MoveLinks(wxDC& dc)
1514 {
1515 GetEventHandler()->OnMoveLinks(dc);
1516 }
1517
1518
1519 void wxShape::Draw(wxDC& dc)
1520 {
1521 if (m_visible)
1522 {
1523 GetEventHandler()->OnDraw(dc);
1524 GetEventHandler()->OnDrawContents(dc);
1525 GetEventHandler()->OnDrawControlPoints(dc);
1526 GetEventHandler()->OnDrawBranches(dc);
1527 }
1528 }
1529
1530 void wxShape::Flash()
1531 {
1532 if (GetCanvas())
1533 {
1534 wxClientDC dc(GetCanvas());
1535 GetCanvas()->PrepareDC(dc);
1536
1537 dc.SetLogicalFunction(OGLRBLF);
1538 Draw(dc);
1539 dc.SetLogicalFunction(wxCOPY);
1540 Draw(dc);
1541 }
1542 }
1543
1544 void wxShape::Show(bool show)
1545 {
1546 m_visible = show;
1547 wxNode *node = m_children.First();
1548 while (node)
1549 {
1550 wxShape *image = (wxShape *)node->Data();
1551 image->Show(show);
1552 node = node->Next();
1553 }
1554 }
1555
1556 void wxShape::Erase(wxDC& dc)
1557 {
1558 GetEventHandler()->OnErase(dc);
1559 GetEventHandler()->OnEraseControlPoints(dc);
1560 GetEventHandler()->OnDrawBranches(dc, TRUE);
1561 }
1562
1563 void wxShape::EraseContents(wxDC& dc)
1564 {
1565 GetEventHandler()->OnEraseContents(dc);
1566 }
1567
1568 void wxShape::AddText(const wxString& string)
1569 {
1570 wxNode *node = m_regions.First();
1571 if (!node)
1572 return;
1573 wxShapeRegion *region = (wxShapeRegion *)node->Data();
1574 region->ClearText();
1575 wxShapeTextLine *new_line =
1576 new wxShapeTextLine(0.0, 0.0, string);
1577 region->GetFormattedText().Append(new_line);
1578
1579 m_formatted = FALSE;
1580 }
1581
1582 void wxShape::SetSize(double x, double y, bool recursive)
1583 {
1584 SetAttachmentSize(x, y);
1585 SetDefaultRegionSize();
1586 }
1587
1588 void wxShape::SetAttachmentSize(double w, double h)
1589 {
1590 double scaleX;
1591 double scaleY;
1592 double width, height;
1593 GetBoundingBoxMin(&width, &height);
1594 if (width == 0.0)
1595 scaleX = 1.0;
1596 else scaleX = w/width;
1597 if (height == 0.0)
1598 scaleY = 1.0;
1599 else scaleY = h/height;
1600
1601 wxNode *node = m_attachmentPoints.First();
1602 while (node)
1603 {
1604 wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
1605 point->m_x = (double)(point->m_x * scaleX);
1606 point->m_y = (double)(point->m_y * scaleY);
1607 node = node->Next();
1608 }
1609 }
1610
1611 // Add line FROM this object
1612 void wxShape::AddLine(wxLineShape *line, wxShape *other,
1613 int attachFrom, int attachTo,
1614 // The line ordering
1615 int positionFrom, int positionTo)
1616 {
1617 if (positionFrom == -1)
1618 {
1619 if (!m_lines.Member(line))
1620 m_lines.Append(line);
1621 }
1622 else
1623 {
1624 // Don't preserve old ordering if we have new ordering instructions
1625 m_lines.DeleteObject(line);
1626 if (positionFrom < m_lines.Number())
1627 {
1628 wxNode* node = m_lines.Nth(positionFrom);
1629 m_lines.Insert(node, line);
1630 }
1631 else
1632 m_lines.Append(line);
1633 }
1634
1635 if (positionTo == -1)
1636 {
1637 if (!other->m_lines.Member(line))
1638 other->m_lines.Append(line);
1639 }
1640 else
1641 {
1642 // Don't preserve old ordering if we have new ordering instructions
1643 other->m_lines.DeleteObject(line);
1644 if (positionTo < other->m_lines.Number())
1645 {
1646 wxNode* node = other->m_lines.Nth(positionTo);
1647 other->m_lines.Insert(node, line);
1648 }
1649 else
1650 other->m_lines.Append(line);
1651 }
1652 #if 0
1653 // Wrong: doesn't preserve ordering of shape already linked
1654 m_lines.DeleteObject(line);
1655 other->m_lines.DeleteObject(line);
1656
1657 if (positionFrom == -1)
1658 m_lines.Append(line);
1659 else
1660 {
1661 if (positionFrom < m_lines.Number())
1662 {
1663 wxNode* node = m_lines.Nth(positionFrom);
1664 m_lines.Insert(node, line);
1665 }
1666 else
1667 m_lines.Append(line);
1668 }
1669
1670 if (positionTo == -1)
1671 other->m_lines.Append(line);
1672 else
1673 {
1674 if (positionTo < other->m_lines.Number())
1675 {
1676 wxNode* node = other->m_lines.Nth(positionTo);
1677 other->m_lines.Insert(node, line);
1678 }
1679 else
1680 other->m_lines.Append(line);
1681 }
1682 #endif
1683
1684 line->SetFrom(this);
1685 line->SetTo(other);
1686 line->SetAttachments(attachFrom, attachTo);
1687 }
1688
1689 void wxShape::RemoveLine(wxLineShape *line)
1690 {
1691 if (line->GetFrom() == this)
1692 line->GetTo()->m_lines.DeleteObject(line);
1693 else
1694 line->GetFrom()->m_lines.DeleteObject(line);
1695
1696 m_lines.DeleteObject(line);
1697 }
1698
1699 #ifdef PROLOGIO
1700 void wxShape::WriteAttributes(wxExpr *clause)
1701 {
1702 clause->AddAttributeValueString("type", GetClassInfo()->GetClassName());
1703 clause->AddAttributeValue("id", m_id);
1704
1705 if (m_pen)
1706 {
1707 int penWidth = m_pen->GetWidth();
1708 int penStyle = m_pen->GetStyle();
1709 if (penWidth != 1)
1710 clause->AddAttributeValue("pen_width", (long)penWidth);
1711 if (penStyle != wxSOLID)
1712 clause->AddAttributeValue("pen_style", (long)penStyle);
1713
1714 wxString penColour = wxTheColourDatabase->FindName(m_pen->GetColour());
1715 if (penColour == "")
1716 {
1717 wxString hex(oglColourToHex(m_pen->GetColour()));
1718 hex = wxString("#") + hex;
1719 clause->AddAttributeValueString("pen_colour", hex);
1720 }
1721 else if (penColour != "BLACK")
1722 clause->AddAttributeValueString("pen_colour", penColour);
1723 }
1724
1725 if (m_brush)
1726 {
1727 wxString brushColour = wxTheColourDatabase->FindName(m_brush->GetColour());
1728
1729 if (brushColour == "")
1730 {
1731 wxString hex(oglColourToHex(m_brush->GetColour()));
1732 hex = wxString("#") + hex;
1733 clause->AddAttributeValueString("brush_colour", hex);
1734 }
1735 else if (brushColour != "WHITE")
1736 clause->AddAttributeValueString("brush_colour", brushColour);
1737
1738 if (m_brush->GetStyle() != wxSOLID)
1739 clause->AddAttributeValue("brush_style", (long)m_brush->GetStyle());
1740 }
1741
1742 // Output line ids
1743
1744 int n_lines = m_lines.Number();
1745 if (n_lines > 0)
1746 {
1747 wxExpr *list = new wxExpr(wxExprList);
1748 wxNode *node = m_lines.First();
1749 while (node)
1750 {
1751 wxShape *line = (wxShape *)node->Data();
1752 wxExpr *id_expr = new wxExpr(line->GetId());
1753 list->Append(id_expr);
1754 node = node->Next();
1755 }
1756 clause->AddAttributeValue("arcs", list);
1757 }
1758
1759 // Miscellaneous members
1760 if (m_attachmentMode != 0)
1761 clause->AddAttributeValue("use_attachments", (long)m_attachmentMode);
1762 if (m_sensitivity != OP_ALL)
1763 clause->AddAttributeValue("sensitivity", (long)m_sensitivity);
1764 if (!m_spaceAttachments)
1765 clause->AddAttributeValue("space_attachments", (long)m_spaceAttachments);
1766 if (m_fixedWidth)
1767 clause->AddAttributeValue("fixed_width", (long)m_fixedWidth);
1768 if (m_fixedHeight)
1769 clause->AddAttributeValue("fixed_height", (long)m_fixedHeight);
1770 if (m_shadowMode != SHADOW_NONE)
1771 clause->AddAttributeValue("shadow_mode", (long)m_shadowMode);
1772 if (m_centreResize != TRUE)
1773 clause->AddAttributeValue("centre_resize", (long)0);
1774 clause->AddAttributeValue("maintain_aspect_ratio", (long) m_maintainAspectRatio);
1775 if (m_highlighted != FALSE)
1776 clause->AddAttributeValue("hilite", (long)m_highlighted);
1777
1778 if (m_parent) // For composite objects
1779 clause->AddAttributeValue("parent", (long)m_parent->GetId());
1780
1781 if (m_rotation != 0.0)
1782 clause->AddAttributeValue("rotation", m_rotation);
1783
1784 if (!this->IsKindOf(CLASSINFO(wxLineShape)))
1785 {
1786 clause->AddAttributeValue("neck_length", (long) m_branchNeckLength);
1787 clause->AddAttributeValue("stem_length", (long) m_branchStemLength);
1788 clause->AddAttributeValue("branch_spacing", (long) m_branchSpacing);
1789 clause->AddAttributeValue("branch_style", (long) m_branchStyle);
1790 }
1791
1792 // Write user-defined attachment points, if any
1793 if (m_attachmentPoints.Number() > 0)
1794 {
1795 wxExpr *attachmentList = new wxExpr(wxExprList);
1796 wxNode *node = m_attachmentPoints.First();
1797 while (node)
1798 {
1799 wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
1800 wxExpr *pointExpr = new wxExpr(wxExprList);
1801 pointExpr->Append(new wxExpr((long)point->m_id));
1802 pointExpr->Append(new wxExpr(point->m_x));
1803 pointExpr->Append(new wxExpr(point->m_y));
1804 attachmentList->Append(pointExpr);
1805 node = node->Next();
1806 }
1807 clause->AddAttributeValue("user_attachments", attachmentList);
1808 }
1809
1810 // Write text regions
1811 WriteRegions(clause);
1812 }
1813
1814 void wxShape::WriteRegions(wxExpr *clause)
1815 {
1816 // Output regions as region1 = (...), region2 = (...), etc
1817 // and formatted text as text1 = (...), text2 = (...) etc.
1818 int regionNo = 1;
1819 char regionNameBuf[20];
1820 char textNameBuf[20];
1821 wxNode *node = m_regions.First();
1822 while (node)
1823 {
1824 wxShapeRegion *region = (wxShapeRegion *)node->Data();
1825 sprintf(regionNameBuf, "region%d", regionNo);
1826 sprintf(textNameBuf, "text%d", regionNo);
1827
1828 // Original text and region attributes:
1829 // region1 = (regionName regionText x y width height minWidth minHeight proportionX proportionY
1830 // formatMode fontSize fontFamily fontStyle fontWeight textColour)
1831 wxExpr *regionExpr = new wxExpr(wxExprList);
1832 regionExpr->Append(new wxExpr(wxExprString, region->m_regionName));
1833 regionExpr->Append(new wxExpr(wxExprString, region->m_regionText));
1834
1835 regionExpr->Append(new wxExpr(region->m_x));
1836 regionExpr->Append(new wxExpr(region->m_y));
1837 regionExpr->Append(new wxExpr(region->GetWidth()));
1838 regionExpr->Append(new wxExpr(region->GetHeight()));
1839
1840 regionExpr->Append(new wxExpr(region->m_minWidth));
1841 regionExpr->Append(new wxExpr(region->m_minHeight));
1842 regionExpr->Append(new wxExpr(region->m_regionProportionX));
1843 regionExpr->Append(new wxExpr(region->m_regionProportionY));
1844
1845 regionExpr->Append(new wxExpr((long)region->m_formatMode));
1846
1847 regionExpr->Append(new wxExpr((long)(region->m_font ? region->m_font->GetPointSize() : 10)));
1848 regionExpr->Append(new wxExpr((long)(region->m_font ? region->m_font->GetFamily() : wxDEFAULT)));
1849 regionExpr->Append(new wxExpr((long)(region->m_font ? region->m_font->GetStyle() : wxDEFAULT)));
1850 regionExpr->Append(new wxExpr((long)(region->m_font ? region->m_font->GetWeight() : wxNORMAL)));
1851 regionExpr->Append(new wxExpr(wxExprString, region->m_textColour));
1852
1853 // New members for pen colour/style
1854 regionExpr->Append(new wxExpr(wxExprString, region->m_penColour));
1855 regionExpr->Append(new wxExpr((long)region->m_penStyle));
1856
1857 // Formatted text:
1858 // text1 = ((x y string) (x y string) ...)
1859 wxExpr *textExpr = new wxExpr(wxExprList);
1860
1861 wxNode *textNode = region->m_formattedText.First();
1862 while (textNode)
1863 {
1864 wxShapeTextLine *line = (wxShapeTextLine *)textNode->Data();
1865 wxExpr *list2 = new wxExpr(wxExprList);
1866 list2->Append(new wxExpr(line->GetX()));
1867 list2->Append(new wxExpr(line->GetY()));
1868 list2->Append(new wxExpr(wxExprString, line->GetText()));
1869 textExpr->Append(list2);
1870 textNode = textNode->Next();
1871 }
1872
1873 // Now add both attributes to the clause
1874 clause->AddAttributeValue(regionNameBuf, regionExpr);
1875 clause->AddAttributeValue(textNameBuf, textExpr);
1876
1877 node = node->Next();
1878 regionNo ++;
1879 }
1880 }
1881
1882 void wxShape::ReadAttributes(wxExpr *clause)
1883 {
1884 clause->GetAttributeValue("id", m_id);
1885 wxRegisterId(m_id);
1886
1887 clause->GetAttributeValue("x", m_xpos);
1888 clause->GetAttributeValue("y", m_ypos);
1889
1890 // Input text strings (FOR COMPATIBILITY WITH OLD FILES ONLY. SEE REGION CODE BELOW.)
1891 ClearText();
1892 wxExpr *strings = clause->AttributeValue("text");
1893 if (strings && strings->Type() == wxExprList)
1894 {
1895 m_formatted = TRUE; // Assume text is formatted unless we prove otherwise
1896 wxExpr *node = strings->value.first;
1897 while (node)
1898 {
1899 wxExpr *string_expr = node;
1900 double the_x = 0.0;
1901 double the_y = 0.0;
1902 wxString the_string("");
1903
1904 // string_expr can either be a string, or a list of
1905 // 3 elements: x, y, and string.
1906 if (string_expr->Type() == wxExprString)
1907 {
1908 the_string = string_expr->StringValue();
1909 m_formatted = FALSE;
1910 }
1911 else if (string_expr->Type() == wxExprList)
1912 {
1913 wxExpr *first = string_expr->value.first;
1914 wxExpr *second = first ? first->next : (wxExpr*) NULL;
1915 wxExpr *third = second ? second->next : (wxExpr*) NULL;
1916
1917 if (first && second && third &&
1918 (first->Type() == wxExprReal || first->Type() == wxExprInteger) &&
1919 (second->Type() == wxExprReal || second->Type() == wxExprInteger) &&
1920 third->Type() == wxExprString)
1921 {
1922 if (first->Type() == wxExprReal)
1923 the_x = first->RealValue();
1924 else the_x = (double)first->IntegerValue();
1925
1926 if (second->Type() == wxExprReal)
1927 the_y = second->RealValue();
1928 else the_y = (double)second->IntegerValue();
1929
1930 the_string = third->StringValue();
1931 }
1932 }
1933 wxShapeTextLine *line =
1934 new wxShapeTextLine(the_x, the_y, (char*) (const char*) the_string);
1935 m_text.Append(line);
1936
1937 node = node->next;
1938 }
1939 }
1940
1941 wxString pen_string = "";
1942 wxString brush_string = "";
1943 int pen_width = 1;
1944 int pen_style = wxSOLID;
1945 int brush_style = wxSOLID;
1946 m_attachmentMode = ATTACHMENT_MODE_NONE;
1947
1948 clause->GetAttributeValue("pen_colour", pen_string);
1949 clause->GetAttributeValue("text_colour", m_textColourName);
1950
1951 SetTextColour(m_textColourName);
1952
1953 clause->GetAttributeValue("region_name", m_regionName);
1954
1955 clause->GetAttributeValue("brush_colour", brush_string);
1956 clause->GetAttributeValue("pen_width", pen_width);
1957 clause->GetAttributeValue("pen_style", pen_style);
1958 clause->GetAttributeValue("brush_style", brush_style);
1959
1960 int iVal = (int) m_attachmentMode;
1961 clause->GetAttributeValue("use_attachments", iVal);
1962 m_attachmentMode = iVal;
1963
1964 clause->GetAttributeValue("sensitivity", m_sensitivity);
1965
1966 iVal = (int) m_spaceAttachments;
1967 clause->GetAttributeValue("space_attachments", iVal);
1968 m_spaceAttachments = (iVal != 0);
1969
1970 iVal = (int) m_fixedWidth;
1971 clause->GetAttributeValue("fixed_width", iVal);
1972 m_fixedWidth = (iVal != 0);
1973
1974 iVal = (int) m_fixedHeight;
1975 clause->GetAttributeValue("fixed_height", iVal);
1976 m_fixedHeight = (iVal != 0);
1977
1978 clause->GetAttributeValue("format_mode", m_formatMode);
1979 clause->GetAttributeValue("shadow_mode", m_shadowMode);
1980
1981 iVal = m_branchNeckLength;
1982 clause->GetAttributeValue("neck_length", iVal);
1983 m_branchNeckLength = iVal;
1984
1985 iVal = m_branchStemLength;
1986 clause->GetAttributeValue("stem_length", iVal);
1987 m_branchStemLength = iVal;
1988
1989 iVal = m_branchSpacing;
1990 clause->GetAttributeValue("branch_spacing", iVal);
1991 m_branchSpacing = iVal;
1992
1993 clause->GetAttributeValue("branch_style", m_branchStyle);
1994
1995 iVal = (int) m_centreResize;
1996 clause->GetAttributeValue("centre_resize", iVal);
1997 m_centreResize = (iVal != 0);
1998
1999 iVal = (int) m_maintainAspectRatio;
2000 clause->GetAttributeValue("maintain_aspect_ratio", iVal);
2001 m_maintainAspectRatio = (iVal != 0);
2002
2003 iVal = (int) m_highlighted;
2004 clause->GetAttributeValue("hilite", iVal);
2005 m_highlighted = (iVal != 0);
2006
2007 clause->GetAttributeValue("rotation", m_rotation);
2008
2009 if (pen_string == "")
2010 pen_string = "BLACK";
2011 if (brush_string == "")
2012 brush_string = "WHITE";
2013
2014 if (pen_string.GetChar(0) == '#')
2015 {
2016 wxColour col(oglHexToColour(pen_string.After('#')));
2017 m_pen = wxThePenList->FindOrCreatePen(col, pen_width, pen_style);
2018 }
2019 else
2020 m_pen = wxThePenList->FindOrCreatePen(pen_string, pen_width, pen_style);
2021
2022 if (!m_pen)
2023 m_pen = wxBLACK_PEN;
2024
2025 if (brush_string.GetChar(0) == '#')
2026 {
2027 wxColour col(oglHexToColour(brush_string.After('#')));
2028 m_brush = wxTheBrushList->FindOrCreateBrush(col, brush_style);
2029 }
2030 else
2031 m_brush = wxTheBrushList->FindOrCreateBrush(brush_string, brush_style);
2032
2033 if (!m_brush)
2034 m_brush = wxWHITE_BRUSH;
2035
2036 int point_size = 10;
2037 clause->GetAttributeValue("point_size", point_size);
2038 SetFont(oglMatchFont(point_size));
2039
2040 // Read user-defined attachment points, if any
2041 wxExpr *attachmentList = clause->AttributeValue("user_attachments");
2042 if (attachmentList)
2043 {
2044 wxExpr *pointExpr = attachmentList->GetFirst();
2045 while (pointExpr)
2046 {
2047 wxExpr *idExpr = pointExpr->Nth(0);
2048 wxExpr *xExpr = pointExpr->Nth(1);
2049 wxExpr *yExpr = pointExpr->Nth(2);
2050 if (idExpr && xExpr && yExpr)
2051 {
2052 wxAttachmentPoint *point = new wxAttachmentPoint;
2053 point->m_id = (int)idExpr->IntegerValue();
2054 point->m_x = xExpr->RealValue();
2055 point->m_y = yExpr->RealValue();
2056 m_attachmentPoints.Append((wxObject *)point);
2057 }
2058 pointExpr = pointExpr->GetNext();
2059 }
2060 }
2061
2062 // Read text regions
2063 ReadRegions(clause);
2064 }
2065
2066 void wxShape::ReadRegions(wxExpr *clause)
2067 {
2068 ClearRegions();
2069
2070 // region1 = (regionName regionText x y width height minWidth minHeight proportionX proportionY
2071 // formatMode fontSize fontFamily fontStyle fontWeight textColour)
2072 int regionNo = 1;
2073 char regionNameBuf[20];
2074 char textNameBuf[20];
2075
2076 wxExpr *regionExpr = NULL;
2077 wxExpr *textExpr = NULL;
2078 sprintf(regionNameBuf, "region%d", regionNo);
2079 sprintf(textNameBuf, "text%d", regionNo);
2080
2081 m_formatted = TRUE; // Assume text is formatted unless we prove otherwise
2082
2083 while ((regionExpr = clause->AttributeValue(regionNameBuf)))
2084 {
2085 /*
2086 * Get the region information
2087 *
2088 */
2089
2090 wxString regionName("");
2091 wxString regionText("");
2092 double x = 0.0;
2093 double y = 0.0;
2094 double width = 0.0;
2095 double height = 0.0;
2096 double minWidth = 5.0;
2097 double minHeight = 5.0;
2098 double m_regionProportionX = -1.0;
2099 double m_regionProportionY = -1.0;
2100 int formatMode = FORMAT_NONE;
2101 int fontSize = 10;
2102 int fontFamily = wxSWISS;
2103 int fontStyle = wxNORMAL;
2104 int fontWeight = wxNORMAL;
2105 wxString regionTextColour("");
2106 wxString penColour("");
2107 int penStyle = wxSOLID;
2108
2109 if (regionExpr->Type() == wxExprList)
2110 {
2111 wxExpr *nameExpr = regionExpr->Nth(0);
2112 wxExpr *textExpr = regionExpr->Nth(1);
2113 wxExpr *xExpr = regionExpr->Nth(2);
2114 wxExpr *yExpr = regionExpr->Nth(3);
2115 wxExpr *widthExpr = regionExpr->Nth(4);
2116 wxExpr *heightExpr = regionExpr->Nth(5);
2117 wxExpr *minWidthExpr = regionExpr->Nth(6);
2118 wxExpr *minHeightExpr = regionExpr->Nth(7);
2119 wxExpr *propXExpr = regionExpr->Nth(8);
2120 wxExpr *propYExpr = regionExpr->Nth(9);
2121 wxExpr *formatExpr = regionExpr->Nth(10);
2122 wxExpr *sizeExpr = regionExpr->Nth(11);
2123 wxExpr *familyExpr = regionExpr->Nth(12);
2124 wxExpr *styleExpr = regionExpr->Nth(13);
2125 wxExpr *weightExpr = regionExpr->Nth(14);
2126 wxExpr *colourExpr = regionExpr->Nth(15);
2127 wxExpr *penColourExpr = regionExpr->Nth(16);
2128 wxExpr *penStyleExpr = regionExpr->Nth(17);
2129
2130 regionName = nameExpr->StringValue();
2131 regionText = textExpr->StringValue();
2132
2133 x = xExpr->RealValue();
2134 y = yExpr->RealValue();
2135
2136 width = widthExpr->RealValue();
2137 height = heightExpr->RealValue();
2138
2139 minWidth = minWidthExpr->RealValue();
2140 minHeight = minHeightExpr->RealValue();
2141
2142 m_regionProportionX = propXExpr->RealValue();
2143 m_regionProportionY = propYExpr->RealValue();
2144
2145 formatMode = (int) formatExpr->IntegerValue();
2146 fontSize = (int)sizeExpr->IntegerValue();
2147 fontFamily = (int)familyExpr->IntegerValue();
2148 fontStyle = (int)styleExpr->IntegerValue();
2149 fontWeight = (int)weightExpr->IntegerValue();
2150
2151 if (colourExpr)
2152 {
2153 regionTextColour = colourExpr->StringValue();
2154 }
2155 else
2156 regionTextColour = "BLACK";
2157
2158 if (penColourExpr)
2159 penColour = penColourExpr->StringValue();
2160 if (penStyleExpr)
2161 penStyle = (int)penStyleExpr->IntegerValue();
2162 }
2163 wxFont *font = wxTheFontList->FindOrCreateFont(fontSize, fontFamily, fontStyle, fontWeight);
2164
2165 wxShapeRegion *region = new wxShapeRegion;
2166 region->SetProportions(m_regionProportionX, m_regionProportionY);
2167 region->SetFont(font);
2168 region->SetSize(width, height);
2169 region->SetPosition(x, y);
2170 region->SetMinSize(minWidth, minHeight);
2171 region->SetFormatMode(formatMode);
2172 region->SetPenStyle(penStyle);
2173 if (penColour != "")
2174 region->SetPenColour(penColour);
2175
2176 region->m_textColour = regionTextColour;
2177 region->m_regionText = regionText;
2178 region->m_regionName = regionName;
2179
2180 m_regions.Append(region);
2181
2182 /*
2183 * Get the formatted text strings
2184 *
2185 */
2186 textExpr = clause->AttributeValue(textNameBuf);
2187 if (textExpr && (textExpr->Type() == wxExprList))
2188 {
2189 wxExpr *node = textExpr->value.first;
2190 while (node)
2191 {
2192 wxExpr *string_expr = node;
2193 double the_x = 0.0;
2194 double the_y = 0.0;
2195 wxString the_string("");
2196
2197 // string_expr can either be a string, or a list of
2198 // 3 elements: x, y, and string.
2199 if (string_expr->Type() == wxExprString)
2200 {
2201 the_string = string_expr->StringValue();
2202 m_formatted = FALSE;
2203 }
2204 else if (string_expr->Type() == wxExprList)
2205 {
2206 wxExpr *first = string_expr->value.first;
2207 wxExpr *second = first ? first->next : (wxExpr*) NULL;
2208 wxExpr *third = second ? second->next : (wxExpr*) NULL;
2209
2210 if (first && second && third &&
2211 (first->Type() == wxExprReal || first->Type() == wxExprInteger) &&
2212 (second->Type() == wxExprReal || second->Type() == wxExprInteger) &&
2213 third->Type() == wxExprString)
2214 {
2215 if (first->Type() == wxExprReal)
2216 the_x = first->RealValue();
2217 else the_x = (double)first->IntegerValue();
2218
2219 if (second->Type() == wxExprReal)
2220 the_y = second->RealValue();
2221 else the_y = (double)second->IntegerValue();
2222
2223 the_string = third->StringValue();
2224 }
2225 }
2226 if (the_string)
2227 {
2228 wxShapeTextLine *line =
2229 new wxShapeTextLine(the_x, the_y, (char*) (const char*) the_string);
2230 region->m_formattedText.Append(line);
2231 }
2232 node = node->next;
2233 }
2234 }
2235
2236 regionNo ++;
2237 sprintf(regionNameBuf, "region%d", regionNo);
2238 sprintf(textNameBuf, "text%d", regionNo);
2239 }
2240
2241 // Compatibility: check for no regions (old file).
2242 // Lines and divided rectangles must deal with this compatibility
2243 // theirselves. Composites _may_ not have any regions anyway.
2244 if ((m_regions.Number() == 0) &&
2245 !this->IsKindOf(CLASSINFO(wxLineShape)) && !this->IsKindOf(CLASSINFO(wxDividedShape)) &&
2246 !this->IsKindOf(CLASSINFO(wxCompositeShape)))
2247 {
2248 wxShapeRegion *newRegion = new wxShapeRegion;
2249 newRegion->SetName("0");
2250 m_regions.Append((wxObject *)newRegion);
2251 if (m_text.Number() > 0)
2252 {
2253 newRegion->ClearText();
2254 wxNode *node = m_text.First();
2255 while (node)
2256 {
2257 wxShapeTextLine *textLine = (wxShapeTextLine *)node->Data();
2258 wxNode *next = node->Next();
2259 newRegion->GetFormattedText().Append((wxObject *)textLine);
2260 delete node;
2261 node = next;
2262 }
2263 }
2264 }
2265 }
2266
2267 #endif
2268
2269 void wxShape::Copy(wxShape& copy)
2270 {
2271 copy.m_id = m_id;
2272 copy.m_xpos = m_xpos;
2273 copy.m_ypos = m_ypos;
2274 copy.m_pen = m_pen;
2275 copy.m_brush = m_brush;
2276 copy.m_textColour = m_textColour;
2277 copy.m_centreResize = m_centreResize;
2278 copy.m_maintainAspectRatio = m_maintainAspectRatio;
2279 copy.m_attachmentMode = m_attachmentMode;
2280 copy.m_spaceAttachments = m_spaceAttachments;
2281 copy.m_highlighted = m_highlighted;
2282 copy.m_rotation = m_rotation;
2283 copy.m_textColourName = m_textColourName;
2284 copy.m_regionName = m_regionName;
2285
2286 copy.m_sensitivity = m_sensitivity;
2287 copy.m_draggable = m_draggable;
2288 copy.m_fixedWidth = m_fixedWidth;
2289 copy.m_fixedHeight = m_fixedHeight;
2290 copy.m_formatMode = m_formatMode;
2291 copy.m_drawHandles = m_drawHandles;
2292
2293 copy.m_visible = m_visible;
2294 copy.m_shadowMode = m_shadowMode;
2295 copy.m_shadowOffsetX = m_shadowOffsetX;
2296 copy.m_shadowOffsetY = m_shadowOffsetY;
2297 copy.m_shadowBrush = m_shadowBrush;
2298
2299 copy.m_branchNeckLength = m_branchNeckLength;
2300 copy.m_branchStemLength = m_branchStemLength;
2301 copy.m_branchSpacing = m_branchSpacing;
2302
2303 // Copy text regions
2304 copy.ClearRegions();
2305 wxNode *node = m_regions.First();
2306 while (node)
2307 {
2308 wxShapeRegion *region = (wxShapeRegion *)node->Data();
2309 wxShapeRegion *newRegion = new wxShapeRegion(*region);
2310 copy.m_regions.Append(newRegion);
2311 node = node->Next();
2312 }
2313
2314 // Copy attachments
2315 copy.ClearAttachments();
2316 node = m_attachmentPoints.First();
2317 while (node)
2318 {
2319 wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
2320 wxAttachmentPoint *newPoint = new wxAttachmentPoint;
2321 newPoint->m_id = point->m_id;
2322 newPoint->m_x = point->m_x;
2323 newPoint->m_y = point->m_y;
2324 copy.m_attachmentPoints.Append((wxObject *)newPoint);
2325 node = node->Next();
2326 }
2327
2328 // Copy lines
2329 copy.m_lines.Clear();
2330 node = m_lines.First();
2331 while (node)
2332 {
2333 wxLineShape* line = (wxLineShape*) node->Data();
2334 copy.m_lines.Append(line);
2335 node = node->Next();
2336 }
2337 }
2338
2339 // Create and return a new, fully copied object.
2340 wxShape *wxShape::CreateNewCopy(bool resetMapping, bool recompute)
2341 {
2342 if (resetMapping)
2343 oglObjectCopyMapping.Clear();
2344
2345 wxShape* newObject = (wxShape*) GetClassInfo()->CreateObject();
2346
2347 wxASSERT( (newObject != NULL) );
2348 wxASSERT( (newObject->IsKindOf(CLASSINFO(wxShape))) );
2349
2350 Copy(*newObject);
2351
2352 if (GetEventHandler() != this)
2353 {
2354 wxShapeEvtHandler* newHandler = GetEventHandler()->CreateNewCopy();
2355 newObject->SetEventHandler(newHandler);
2356 newObject->SetPreviousHandler(NULL);
2357 newHandler->SetPreviousHandler(newObject);
2358 newHandler->SetShape(newObject);
2359 }
2360
2361 if (recompute)
2362 newObject->Recompute();
2363 return newObject;
2364 }
2365
2366 // Does the copying for this object, including copying event
2367 // handler data if any. Calls the virtual Copy function.
2368 void wxShape::CopyWithHandler(wxShape& copy)
2369 {
2370 Copy(copy);
2371
2372 if (GetEventHandler() != this)
2373 {
2374 wxASSERT( copy.GetEventHandler() != NULL );
2375 wxASSERT( copy.GetEventHandler() != (&copy) );
2376 wxASSERT( GetEventHandler()->GetClassInfo() == copy.GetEventHandler()->GetClassInfo() );
2377 GetEventHandler()->CopyData(* (copy.GetEventHandler()));
2378 }
2379 }
2380
2381
2382 // Default - make 6 control points
2383 void wxShape::MakeControlPoints()
2384 {
2385 double maxX, maxY, minX, minY;
2386
2387 GetBoundingBoxMax(&maxX, &maxY);
2388 GetBoundingBoxMin(&minX, &minY);
2389
2390 double widthMin = (double)(minX + CONTROL_POINT_SIZE + 2);
2391 double heightMin = (double)(minY + CONTROL_POINT_SIZE + 2);
2392
2393 // Offsets from main object
2394 double top = (double)(- (heightMin / 2.0));
2395 double bottom = (double)(heightMin / 2.0 + (maxY - minY));
2396 double left = (double)(- (widthMin / 2.0));
2397 double right = (double)(widthMin / 2.0 + (maxX - minX));
2398
2399 wxControlPoint *control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, top,
2400 CONTROL_POINT_DIAGONAL);
2401 m_canvas->AddShape(control);
2402 m_controlPoints.Append(control);
2403
2404 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, 0, top,
2405 CONTROL_POINT_VERTICAL);
2406 m_canvas->AddShape(control);
2407 m_controlPoints.Append(control);
2408
2409 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, top,
2410 CONTROL_POINT_DIAGONAL);
2411 m_canvas->AddShape(control);
2412 m_controlPoints.Append(control);
2413
2414 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, 0,
2415 CONTROL_POINT_HORIZONTAL);
2416 m_canvas->AddShape(control);
2417 m_controlPoints.Append(control);
2418
2419 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, bottom,
2420 CONTROL_POINT_DIAGONAL);
2421 m_canvas->AddShape(control);
2422 m_controlPoints.Append(control);
2423
2424 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, 0, bottom,
2425 CONTROL_POINT_VERTICAL);
2426 m_canvas->AddShape(control);
2427 m_controlPoints.Append(control);
2428
2429 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, bottom,
2430 CONTROL_POINT_DIAGONAL);
2431 m_canvas->AddShape(control);
2432 m_controlPoints.Append(control);
2433
2434 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, 0,
2435 CONTROL_POINT_HORIZONTAL);
2436 m_canvas->AddShape(control);
2437 m_controlPoints.Append(control);
2438
2439 }
2440
2441 void wxShape::MakeMandatoryControlPoints()
2442 {
2443 wxNode *node = m_children.First();
2444 while (node)
2445 {
2446 wxShape *child = (wxShape *)node->Data();
2447 child->MakeMandatoryControlPoints();
2448 node = node->Next();
2449 }
2450 }
2451
2452 void wxShape::ResetMandatoryControlPoints()
2453 {
2454 wxNode *node = m_children.First();
2455 while (node)
2456 {
2457 wxShape *child = (wxShape *)node->Data();
2458 child->ResetMandatoryControlPoints();
2459 node = node->Next();
2460 }
2461 }
2462
2463 void wxShape::ResetControlPoints()
2464 {
2465 ResetMandatoryControlPoints();
2466
2467 if (m_controlPoints.Number() < 1)
2468 return;
2469
2470 double maxX, maxY, minX, minY;
2471
2472 GetBoundingBoxMax(&maxX, &maxY);
2473 GetBoundingBoxMin(&minX, &minY);
2474
2475 double widthMin = (double)(minX + CONTROL_POINT_SIZE + 2);
2476 double heightMin = (double)(minY + CONTROL_POINT_SIZE + 2);
2477
2478 // Offsets from main object
2479 double top = (double)(- (heightMin / 2.0));
2480 double bottom = (double)(heightMin / 2.0 + (maxY - minY));
2481 double left = (double)(- (widthMin / 2.0));
2482 double right = (double)(widthMin / 2.0 + (maxX - minX));
2483
2484 wxNode *node = m_controlPoints.First();
2485 wxControlPoint *control = (wxControlPoint *)node->Data();
2486 control->m_xoffset = left; control->m_yoffset = top;
2487
2488 node = node->Next(); control = (wxControlPoint *)node->Data();
2489 control->m_xoffset = 0; control->m_yoffset = top;
2490
2491 node = node->Next(); control = (wxControlPoint *)node->Data();
2492 control->m_xoffset = right; control->m_yoffset = top;
2493
2494 node = node->Next(); control = (wxControlPoint *)node->Data();
2495 control->m_xoffset = right; control->m_yoffset = 0;
2496
2497 node = node->Next(); control = (wxControlPoint *)node->Data();
2498 control->m_xoffset = right; control->m_yoffset = bottom;
2499
2500 node = node->Next(); control = (wxControlPoint *)node->Data();
2501 control->m_xoffset = 0; control->m_yoffset = bottom;
2502
2503 node = node->Next(); control = (wxControlPoint *)node->Data();
2504 control->m_xoffset = left; control->m_yoffset = bottom;
2505
2506 node = node->Next(); control = (wxControlPoint *)node->Data();
2507 control->m_xoffset = left; control->m_yoffset = 0;
2508 }
2509
2510 void wxShape::DeleteControlPoints(wxDC *dc)
2511 {
2512 wxNode *node = m_controlPoints.First();
2513 while (node)
2514 {
2515 wxControlPoint *control = (wxControlPoint *)node->Data();
2516 if (dc)
2517 control->GetEventHandler()->OnErase(*dc);
2518 m_canvas->RemoveShape(control);
2519 delete control;
2520 delete node;
2521 node = m_controlPoints.First();
2522 }
2523 // Children of divisions are contained objects,
2524 // so stop here
2525 if (!IsKindOf(CLASSINFO(wxDivisionShape)))
2526 {
2527 node = m_children.First();
2528 while (node)
2529 {
2530 wxShape *child = (wxShape *)node->Data();
2531 child->DeleteControlPoints(dc);
2532 node = node->Next();
2533 }
2534 }
2535 }
2536
2537 void wxShape::OnDrawControlPoints(wxDC& dc)
2538 {
2539 if (!m_drawHandles)
2540 return;
2541
2542 dc.SetBrush(* wxBLACK_BRUSH);
2543 dc.SetPen(* wxBLACK_PEN);
2544
2545 wxNode *node = m_controlPoints.First();
2546 while (node)
2547 {
2548 wxControlPoint *control = (wxControlPoint *)node->Data();
2549 control->Draw(dc);
2550 node = node->Next();
2551 }
2552 // Children of divisions are contained objects,
2553 // so stop here.
2554 // This test bypasses the type facility for speed
2555 // (critical when drawing)
2556 if (!IsKindOf(CLASSINFO(wxDivisionShape)))
2557 {
2558 node = m_children.First();
2559 while (node)
2560 {
2561 wxShape *child = (wxShape *)node->Data();
2562 child->GetEventHandler()->OnDrawControlPoints(dc);
2563 node = node->Next();
2564 }
2565 }
2566 }
2567
2568 void wxShape::OnEraseControlPoints(wxDC& dc)
2569 {
2570 wxNode *node = m_controlPoints.First();
2571 while (node)
2572 {
2573 wxControlPoint *control = (wxControlPoint *)node->Data();
2574 control->Erase(dc);
2575 node = node->Next();
2576 }
2577 if (!IsKindOf(CLASSINFO(wxDivisionShape)))
2578 {
2579 node = m_children.First();
2580 while (node)
2581 {
2582 wxShape *child = (wxShape *)node->Data();
2583 child->GetEventHandler()->OnEraseControlPoints(dc);
2584 node = node->Next();
2585 }
2586 }
2587 }
2588
2589 void wxShape::Select(bool select, wxDC* dc)
2590 {
2591 m_selected = select;
2592 if (select)
2593 {
2594 MakeControlPoints();
2595 // Children of divisions are contained objects,
2596 // so stop here
2597 if (!IsKindOf(CLASSINFO(wxDivisionShape)))
2598 {
2599 wxNode *node = m_children.First();
2600 while (node)
2601 {
2602 wxShape *child = (wxShape *)node->Data();
2603 child->MakeMandatoryControlPoints();
2604 node = node->Next();
2605 }
2606 }
2607 if (dc)
2608 GetEventHandler()->OnDrawControlPoints(*dc);
2609 }
2610 if (!select)
2611 {
2612 DeleteControlPoints(dc);
2613 if (!IsKindOf(CLASSINFO(wxDivisionShape)))
2614 {
2615 wxNode *node = m_children.First();
2616 while (node)
2617 {
2618 wxShape *child = (wxShape *)node->Data();
2619 child->DeleteControlPoints(dc);
2620 node = node->Next();
2621 }
2622 }
2623 }
2624 }
2625
2626 bool wxShape::Selected() const
2627 {
2628 return m_selected;
2629 }
2630
2631 bool wxShape::AncestorSelected() const
2632 {
2633 if (m_selected) return TRUE;
2634 if (!GetParent())
2635 return FALSE;
2636 else
2637 return GetParent()->AncestorSelected();
2638 }
2639
2640 int wxShape::GetNumberOfAttachments() const
2641 {
2642 // Should return the MAXIMUM attachment point id here,
2643 // so higher-level functions can iterate through all attachments,
2644 // even if they're not contiguous.
2645 if (m_attachmentPoints.Number() == 0)
2646 return 4;
2647 else
2648 {
2649 int maxN = 3;
2650 wxNode *node = m_attachmentPoints.First();
2651 while (node)
2652 {
2653 wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
2654 if (point->m_id > maxN)
2655 maxN = point->m_id;
2656 node = node->Next();
2657 }
2658 return maxN+1;;
2659 }
2660 }
2661
2662 bool wxShape::AttachmentIsValid(int attachment) const
2663 {
2664 if (m_attachmentPoints.Number() == 0)
2665 {
2666 return ((attachment >= 0) && (attachment < 4)) ;
2667 }
2668
2669 wxNode *node = m_attachmentPoints.First();
2670 while (node)
2671 {
2672 wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
2673 if (point->m_id == attachment)
2674 return TRUE;
2675 node = node->Next();
2676 }
2677 return FALSE;
2678 }
2679
2680 bool wxShape::GetAttachmentPosition(int attachment, double *x, double *y,
2681 int nth, int no_arcs, wxLineShape *line)
2682 {
2683 if (m_attachmentMode == ATTACHMENT_MODE_NONE)
2684 {
2685 *x = m_xpos; *y = m_ypos;
2686 return TRUE;
2687 }
2688 else if (m_attachmentMode == ATTACHMENT_MODE_BRANCHING)
2689 {
2690 wxRealPoint pt, stemPt;
2691 GetBranchingAttachmentPoint(attachment, nth, pt, stemPt);
2692 *x = pt.x;
2693 *y = pt.y;
2694 return TRUE;
2695 }
2696 else if (m_attachmentMode == ATTACHMENT_MODE_EDGE)
2697 {
2698 if (m_attachmentPoints.Number() > 0)
2699 {
2700 wxNode *node = m_attachmentPoints.First();
2701 while (node)
2702 {
2703 wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
2704 if (point->m_id == attachment)
2705 {
2706 *x = (double)(m_xpos + point->m_x);
2707 *y = (double)(m_ypos + point->m_y);
2708 return TRUE;
2709 }
2710 node = node->Next();
2711 }
2712 *x = m_xpos; *y = m_ypos;
2713 return FALSE;
2714 }
2715 else
2716 {
2717 // Assume is rectangular
2718 double w, h;
2719 GetBoundingBoxMax(&w, &h);
2720 double top = (double)(m_ypos + h/2.0);
2721 double bottom = (double)(m_ypos - h/2.0);
2722 double left = (double)(m_xpos - w/2.0);
2723 double right = (double)(m_xpos + w/2.0);
2724
2725 bool isEnd = (line && line->IsEnd(this));
2726
2727 int physicalAttachment = LogicalToPhysicalAttachment(attachment);
2728
2729 // Simplified code
2730 switch (physicalAttachment)
2731 {
2732 case 0:
2733 {
2734 wxRealPoint pt = CalcSimpleAttachment(wxRealPoint(left, bottom), wxRealPoint(right, bottom),
2735 nth, no_arcs, line);
2736
2737 *x = pt.x; *y = pt.y;
2738 break;
2739 }
2740 case 1:
2741 {
2742 wxRealPoint pt = CalcSimpleAttachment(wxRealPoint(right, bottom), wxRealPoint(right, top),
2743 nth, no_arcs, line);
2744
2745 *x = pt.x; *y = pt.y;
2746 break;
2747 }
2748 case 2:
2749 {
2750 wxRealPoint pt = CalcSimpleAttachment(wxRealPoint(left, top), wxRealPoint(right, top),
2751 nth, no_arcs, line);
2752
2753 *x = pt.x; *y = pt.y;
2754 break;
2755 }
2756 case 3:
2757 {
2758 wxRealPoint pt = CalcSimpleAttachment(wxRealPoint(left, bottom), wxRealPoint(left, top),
2759 nth, no_arcs, line);
2760
2761 *x = pt.x; *y = pt.y;
2762 break;
2763 }
2764 default:
2765 {
2766 return FALSE;
2767 break;
2768 }
2769 }
2770 return TRUE;
2771 }
2772 }
2773 return FALSE;
2774 }
2775
2776 void wxShape::GetBoundingBoxMax(double *w, double *h)
2777 {
2778 double ww, hh;
2779 GetBoundingBoxMin(&ww, &hh);
2780 if (m_shadowMode != SHADOW_NONE)
2781 {
2782 ww += m_shadowOffsetX;
2783 hh += m_shadowOffsetY;
2784 }
2785 *w = ww;
2786 *h = hh;
2787 }
2788
2789 // Returns TRUE if image is a descendant of this composite
2790 bool wxShape::HasDescendant(wxShape *image)
2791 {
2792 if (image == this)
2793 return TRUE;
2794 wxNode *node = m_children.First();
2795 while (node)
2796 {
2797 wxShape *child = (wxShape *)node->Data();
2798 bool ans = child->HasDescendant(image);
2799 if (ans)
2800 return TRUE;
2801 node = node->Next();
2802 }
2803 return FALSE;
2804 }
2805
2806 // Clears points from a list of wxRealPoints, and clears list
2807 void wxShape::ClearPointList(wxList& list)
2808 {
2809 wxNode* node = list.First();
2810 while (node)
2811 {
2812 wxRealPoint* pt = (wxRealPoint*) node->Data();
2813 delete pt;
2814
2815 node = node->Next();
2816 }
2817 list.Clear();
2818 }
2819
2820 // Assuming the attachment lies along a vertical or horizontal line,
2821 // calculate the position on that point.
2822 wxRealPoint wxShape::CalcSimpleAttachment(const wxRealPoint& pt1, const wxRealPoint& pt2,
2823 int nth, int noArcs, wxLineShape* line)
2824 {
2825 bool isEnd = (line && line->IsEnd(this));
2826
2827 // Are we horizontal or vertical?
2828 bool isHorizontal = (oglRoughlyEqual(pt1.y, pt2.y) == TRUE);
2829
2830 double x, y;
2831
2832 if (isHorizontal)
2833 {
2834 wxRealPoint firstPoint, secondPoint;
2835 if (pt1.x > pt2.x)
2836 {
2837 firstPoint = pt2;
2838 secondPoint = pt1;
2839 }
2840 else
2841 {
2842 firstPoint = pt1;
2843 secondPoint = pt2;
2844 }
2845
2846 if (m_spaceAttachments)
2847 {
2848 if (line && (line->GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE))
2849 {
2850 // Align line according to the next handle along
2851 wxRealPoint *point = line->GetNextControlPoint(this);
2852 if (point->x < firstPoint.x)
2853 x = firstPoint.x;
2854 else if (point->x > secondPoint.x)
2855 x = secondPoint.x;
2856 else
2857 x = point->x;
2858 }
2859 else
2860 x = firstPoint.x + (nth + 1)*(secondPoint.x - firstPoint.x)/(noArcs + 1);
2861 }
2862 else x = (secondPoint.x - firstPoint.x)/2.0; // Midpoint
2863
2864 y = pt1.y;
2865 }
2866 else
2867 {
2868 wxASSERT( oglRoughlyEqual(pt1.x, pt2.x) == TRUE );
2869
2870 wxRealPoint firstPoint, secondPoint;
2871 if (pt1.y > pt2.y)
2872 {
2873 firstPoint = pt2;
2874 secondPoint = pt1;
2875 }
2876 else
2877 {
2878 firstPoint = pt1;
2879 secondPoint = pt2;
2880 }
2881
2882 if (m_spaceAttachments)
2883 {
2884 if (line && (line->GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE))
2885 {
2886 // Align line according to the next handle along
2887 wxRealPoint *point = line->GetNextControlPoint(this);
2888 if (point->y < firstPoint.y)
2889 y = firstPoint.y;
2890 else if (point->y > secondPoint.y)
2891 y = secondPoint.y;
2892 else
2893 y = point->y;
2894 }
2895 else
2896 y = firstPoint.y + (nth + 1)*(secondPoint.y - firstPoint.y)/(noArcs + 1);
2897 }
2898 else y = (secondPoint.y - firstPoint.y)/2.0; // Midpoint
2899
2900 x = pt1.x;
2901 }
2902
2903 return wxRealPoint(x, y);
2904 }
2905
2906 // Return the zero-based position in m_lines of line.
2907 int wxShape::GetLinePosition(wxLineShape* line)
2908 {
2909 int i = 0;
2910 for (i = 0; i < m_lines.Number(); i++)
2911 if ((wxLineShape*) (m_lines.Nth(i)->Data()) == line)
2912 return i;
2913
2914 return 0;
2915 }
2916
2917 //
2918 // |________|
2919 // | <- root
2920 // | <- neck
2921 // shoulder1 ->---------<- shoulder2
2922 // | | | | |
2923 // <- branching attachment point N-1
2924
2925 // This function gets information about where branching connections go.
2926 // Returns FALSE if there are no lines at this attachment.
2927 bool wxShape::GetBranchingAttachmentInfo(int attachment, wxRealPoint& root, wxRealPoint& neck,
2928 wxRealPoint& shoulder1, wxRealPoint& shoulder2)
2929 {
2930 int physicalAttachment = LogicalToPhysicalAttachment(attachment);
2931
2932 // Number of lines at this attachment.
2933 int lineCount = GetAttachmentLineCount(attachment);
2934
2935 if (lineCount == 0)
2936 return FALSE;
2937
2938 int totalBranchLength = m_branchSpacing * (lineCount - 1);
2939
2940 root = GetBranchingAttachmentRoot(attachment);
2941
2942 // Assume that we have attachment points 0 to 3: top, right, bottom, left.
2943 switch (physicalAttachment)
2944 {
2945 case 0:
2946 {
2947 neck.x = GetX();
2948 neck.y = root.y - m_branchNeckLength;
2949
2950 shoulder1.x = root.x - (totalBranchLength/2.0) ;
2951 shoulder2.x = root.x + (totalBranchLength/2.0) ;
2952
2953 shoulder1.y = neck.y;
2954 shoulder2.y = neck.y;
2955 break;
2956 }
2957 case 1:
2958 {
2959 neck.x = root.x + m_branchNeckLength;
2960 neck.y = root.y;
2961
2962 shoulder1.x = neck.x ;
2963 shoulder2.x = neck.x ;
2964
2965 shoulder1.y = neck.y - (totalBranchLength/2.0) ;
2966 shoulder2.y = neck.y + (totalBranchLength/2.0) ;
2967 break;
2968 }
2969 case 2:
2970 {
2971 neck.x = GetX();
2972 neck.y = root.y + m_branchNeckLength;
2973
2974 shoulder1.x = root.x - (totalBranchLength/2.0) ;
2975 shoulder2.x = root.x + (totalBranchLength/2.0) ;
2976
2977 shoulder1.y = neck.y;
2978 shoulder2.y = neck.y;
2979 break;
2980 }
2981 case 3:
2982 {
2983 neck.x = root.x - m_branchNeckLength;
2984 neck.y = root.y ;
2985
2986 shoulder1.x = neck.x ;
2987 shoulder2.x = neck.x ;
2988
2989 shoulder1.y = neck.y - (totalBranchLength/2.0) ;
2990 shoulder2.y = neck.y + (totalBranchLength/2.0) ;
2991 break;
2992 }
2993 default:
2994 {
2995 wxFAIL_MSG( "Unrecognised attachment point in GetBranchingAttachmentInfo." );
2996 break;
2997 }
2998 }
2999 return TRUE;
3000 }
3001
3002 // n is the number of the adjoining line, from 0 to N-1 where N is the number of lines
3003 // at this attachment point.
3004 // Get the attachment point where the arc joins the stem, and also the point where the
3005 // the stem meets the shoulder.
3006 bool wxShape::GetBranchingAttachmentPoint(int attachment, int n, wxRealPoint& pt, wxRealPoint& stemPt)
3007 {
3008 int physicalAttachment = LogicalToPhysicalAttachment(attachment);
3009
3010 wxRealPoint root, neck, shoulder1, shoulder2;
3011 GetBranchingAttachmentInfo(attachment, root, neck, shoulder1, shoulder2);
3012
3013 // Assume that we have attachment points 0 to 3: top, right, bottom, left.
3014 switch (physicalAttachment)
3015 {
3016 case 0:
3017 {
3018 pt.y = neck.y - m_branchStemLength;
3019 pt.x = shoulder1.x + n*m_branchSpacing;
3020
3021 stemPt.x = pt.x;
3022 stemPt.y = neck.y;
3023 break;
3024 }
3025 case 2:
3026 {
3027 pt.y = neck.y + m_branchStemLength;
3028 pt.x = shoulder1.x + n*m_branchSpacing;
3029
3030 stemPt.x = pt.x;
3031 stemPt.y = neck.y;
3032 break;
3033 }
3034 case 1:
3035 {
3036 pt.x = neck.x + m_branchStemLength;
3037 pt.y = shoulder1.y + n*m_branchSpacing;
3038
3039 stemPt.x = neck.x;
3040 stemPt.y = pt.y;
3041 break;
3042 }
3043 case 3:
3044 {
3045 pt.x = neck.x - m_branchStemLength;
3046 pt.y = shoulder1.y + n*m_branchSpacing;
3047
3048 stemPt.x = neck.x;
3049 stemPt.y = pt.y;
3050 break;
3051 }
3052 default:
3053 {
3054 wxFAIL_MSG( "Unrecognised attachment point in GetBranchingAttachmentPoint." );
3055 break;
3056 }
3057 }
3058
3059 return TRUE;
3060 }
3061
3062 // Get the number of lines at this attachment position.
3063 int wxShape::GetAttachmentLineCount(int attachment) const
3064 {
3065 int count = 0;
3066 wxNode* node = m_lines.First();
3067 while (node)
3068 {
3069 wxLineShape* lineShape = (wxLineShape*) node->Data();
3070 if ((lineShape->GetFrom() == this) && (lineShape->GetAttachmentFrom() == attachment))
3071 count ++;
3072 else if ((lineShape->GetTo() == this) && (lineShape->GetAttachmentTo() == attachment))
3073 count ++;
3074
3075 node = node->Next();
3076 }
3077 return count;
3078 }
3079
3080 // This function gets the root point at the given attachment.
3081 wxRealPoint wxShape::GetBranchingAttachmentRoot(int attachment)
3082 {
3083 int physicalAttachment = LogicalToPhysicalAttachment(attachment);
3084
3085 wxRealPoint root;
3086
3087 double width, height;
3088 GetBoundingBoxMax(& width, & height);
3089
3090 // Assume that we have attachment points 0 to 3: top, right, bottom, left.
3091 switch (physicalAttachment)
3092 {
3093 case 0:
3094 {
3095 root.x = GetX() ;
3096 root.y = GetY() - height/2.0;
3097 break;
3098 }
3099 case 1:
3100 {
3101 root.x = GetX() + width/2.0;
3102 root.y = GetY() ;
3103 break;
3104 }
3105 case 2:
3106 {
3107 root.x = GetX() ;
3108 root.y = GetY() + height/2.0;
3109 break;
3110 }
3111 case 3:
3112 {
3113 root.x = GetX() - width/2.0;
3114 root.y = GetY() ;
3115 break;
3116 }
3117 default:
3118 {
3119 wxFAIL_MSG( "Unrecognised attachment point in GetBranchingAttachmentRoot." );
3120 break;
3121 }
3122 }
3123 return root;
3124 }
3125
3126 // Draw or erase the branches (not the actual arcs though)
3127 void wxShape::OnDrawBranches(wxDC& dc, int attachment, bool erase)
3128 {
3129 int count = GetAttachmentLineCount(attachment);
3130 if (count == 0)
3131 return;
3132
3133 wxRealPoint root, neck, shoulder1, shoulder2;
3134 GetBranchingAttachmentInfo(attachment, root, neck, shoulder1, shoulder2);
3135
3136 if (erase)
3137 {
3138 dc.SetPen(*wxWHITE_PEN);
3139 dc.SetBrush(*wxWHITE_BRUSH);
3140 }
3141 else
3142 {
3143 dc.SetPen(*wxBLACK_PEN);
3144 dc.SetBrush(*wxBLACK_BRUSH);
3145 }
3146
3147 // Draw neck
3148 dc.DrawLine((long) root.x, (long) root.y, (long) neck.x, (long) neck.y);
3149
3150 if (count > 1)
3151 {
3152 // Draw shoulder-to-shoulder line
3153 dc.DrawLine((long) shoulder1.x, (long) shoulder1.y, (long) shoulder2.x, (long) shoulder2.y);
3154 }
3155 // Draw all the little branches
3156 int i;
3157 for (i = 0; i < count; i++)
3158 {
3159 wxRealPoint pt, stemPt;
3160 GetBranchingAttachmentPoint(attachment, i, pt, stemPt);
3161 dc.DrawLine((long) stemPt.x, (long) stemPt.y, (long) pt.x, (long) pt.y);
3162
3163 if ((GetBranchStyle() & BRANCHING_ATTACHMENT_BLOB) && (count > 1))
3164 {
3165 long blobSize=6;
3166 // dc.DrawEllipse((long) (stemPt.x + 0.5 - (blobSize/2.0)), (long) (stemPt.y + 0.5 - (blobSize/2.0)), blobSize, blobSize);
3167 dc.DrawEllipse((long) (stemPt.x - (blobSize/2.0)), (long) (stemPt.y - (blobSize/2.0)), blobSize, blobSize);
3168 }
3169 }
3170 }
3171
3172 // Draw or erase the branches (not the actual arcs though)
3173 void wxShape::OnDrawBranches(wxDC& dc, bool erase)
3174 {
3175 if (m_attachmentMode != ATTACHMENT_MODE_BRANCHING)
3176 return;
3177
3178 int count = GetNumberOfAttachments();
3179 int i;
3180 for (i = 0; i < count; i++)
3181 OnDrawBranches(dc, i, erase);
3182 }
3183
3184 // Only get the attachment position at the _edge_ of the shape, ignoring
3185 // branching mode. This is used e.g. to indicate the edge of interest, not the point
3186 // on the attachment branch.
3187 bool wxShape::GetAttachmentPositionEdge(int attachment, double *x, double *y,
3188 int nth, int no_arcs, wxLineShape *line)
3189 {
3190 int oldMode = m_attachmentMode;
3191
3192 // Calculate as if to edge, not branch
3193 if (m_attachmentMode == ATTACHMENT_MODE_BRANCHING)
3194 m_attachmentMode = ATTACHMENT_MODE_EDGE;
3195 bool success = GetAttachmentPosition(attachment, x, y, nth, no_arcs, line);
3196 m_attachmentMode = oldMode;
3197
3198 return success;
3199 }
3200
3201 // Rotate the standard attachment point from physical (0 is always North)
3202 // to logical (0 -> 1 if rotated by 90 degrees)
3203 int wxShape::PhysicalToLogicalAttachment(int physicalAttachment) const
3204 {
3205 const double pi = 3.1415926535897932384626433832795 ;
3206 int i;
3207 if (oglRoughlyEqual(GetRotation(), 0.0))
3208 {
3209 i = physicalAttachment;
3210 }
3211 else if (oglRoughlyEqual(GetRotation(), (pi/2.0)))
3212 {
3213 i = physicalAttachment - 1;
3214 }
3215 else if (oglRoughlyEqual(GetRotation(), pi))
3216 {
3217 i = physicalAttachment - 2;
3218 }
3219 else if (oglRoughlyEqual(GetRotation(), (3.0*pi/2.0)))
3220 {
3221 i = physicalAttachment - 3;
3222 }
3223 else
3224 // Can't handle -- assume the same.
3225 return physicalAttachment;
3226
3227 if (i < 0)
3228 i += 4;
3229
3230 return i;
3231 }
3232
3233 // Rotate the standard attachment point from logical
3234 // to physical (0 is always North)
3235 int wxShape::LogicalToPhysicalAttachment(int logicalAttachment) const
3236 {
3237 const double pi = 3.1415926535897932384626433832795 ;
3238 int i;
3239 if (oglRoughlyEqual(GetRotation(), 0.0))
3240 {
3241 i = logicalAttachment;
3242 }
3243 else if (oglRoughlyEqual(GetRotation(), (pi/2.0)))
3244 {
3245 i = logicalAttachment + 1;
3246 }
3247 else if (oglRoughlyEqual(GetRotation(), pi))
3248 {
3249 i = logicalAttachment + 2;
3250 }
3251 else if (oglRoughlyEqual(GetRotation(), (3.0*pi/2.0)))
3252 {
3253 i = logicalAttachment + 3;
3254 }
3255 else
3256 // Can't handle -- assume the same.
3257 return logicalAttachment;
3258
3259 if (i > 3)
3260 i -= 4;
3261
3262 return i;
3263 }
3264
3265 void wxShape::Rotate(double WXUNUSED(x), double WXUNUSED(y), double theta)
3266 {
3267 const double pi = 3.1415926535897932384626433832795 ;
3268 m_rotation = theta;
3269 if (m_rotation < 0.0)
3270 {
3271 m_rotation += 2*pi;
3272 }
3273 else if (m_rotation > 2*pi)
3274 {
3275 m_rotation -= 2*pi;
3276 }
3277 }
3278