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